Merge branch 'integration_2020_wk30' into 'develop'
Integration branch 2020 week 30 - MR 854 : NR_DCI_01 - MR 857 : improve_ue_stability - MR 839 : mac-flexran-improvements
This commit is contained in:
@@ -1830,6 +1830,7 @@ set (MAC_SRC
|
||||
${MAC_DIR}/eNB_scheduler_fairRR.c
|
||||
${MAC_DIR}/eNB_scheduler_phytest.c
|
||||
${MAC_DIR}/pre_processor.c
|
||||
${MAC_DIR}/slicing/slicing.c
|
||||
${MAC_DIR}/config.c
|
||||
${MAC_DIR}/config_ue.c
|
||||
)
|
||||
|
||||
@@ -1120,6 +1120,7 @@ typedef struct
|
||||
uint16_t ul_dmrs_symb_pos;
|
||||
uint8_t dmrs_config_type;
|
||||
uint16_t ul_dmrs_scrambling_id;
|
||||
uint16_t pusch_identity;
|
||||
uint8_t scid;
|
||||
uint8_t num_dmrs_cdm_grps_no_data;
|
||||
uint16_t dmrs_ports;//DMRS ports. [TS38.212 7.3.1.1.2] provides description between DCI 0-1 content and DMRS ports. Bitmap occupying the 11 LSBs with: bit 0: antenna port 1000 bit 11: antenna port 1011 and for each bit 0: DMRS port not used 1: DMRS port used
|
||||
|
||||
@@ -214,7 +214,8 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
|
||||
printf("[DEMOD] I am assuming only TB1 is active, it is in cw %d\n", dlsch1_harq->codeword);
|
||||
#endif
|
||||
|
||||
AssertFatal(1 == 0, "[UE][FATAL] DLSCH: TB0 not active and TB1 active case is not supported\n");
|
||||
LOG_E(PHY, "[UE][FATAL] DLSCH: TB0 not active and TB1 active case is not supported\n");
|
||||
return -1;
|
||||
|
||||
} else {
|
||||
LOG_E(PHY,"[UE][FATAL] nr_tti_rx %d: no active DLSCH\n", nr_tti_rx);
|
||||
@@ -224,14 +225,16 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
|
||||
break;
|
||||
|
||||
default:
|
||||
AssertFatal(1 == 0, "[UE][FATAL] nr_tti_rx %d: Unknown PDSCH format %d\n", nr_tti_rx, type);
|
||||
LOG_E(PHY, "[UE][FATAL] nr_tti_rx %d: Unknown PDSCH format %d\n", nr_tti_rx, type);
|
||||
return(-1);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (dlsch0_harq == NULL)
|
||||
AssertFatal(1 == 0, "Done\n");
|
||||
if (dlsch0_harq == NULL) {
|
||||
LOG_E(PHY, "Done\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
dlsch0_harq->Qm = nr_get_Qm_dl(dlsch[0]->harq_processes[harq_pid]->mcs, dlsch[0]->harq_processes[harq_pid]->mcs_table);
|
||||
dlsch0_harq->R = nr_get_code_rate_dl(dlsch[0]->harq_processes[harq_pid]->mcs, dlsch[0]->harq_processes[harq_pid]->mcs_table);
|
||||
|
||||
@@ -160,6 +160,7 @@ void nr_schedule_response(NR_Sched_Rsp_t *Sched_INFO){
|
||||
gNB->dlsch[i][0]->harq_mask=0;
|
||||
}
|
||||
gNB->pdcch_pdu = NULL;
|
||||
gNB->ul_dci_pdu = NULL;
|
||||
gNB->pbch_configured=0;
|
||||
|
||||
for (int i=0;i<number_dl_pdu;i++) {
|
||||
|
||||
@@ -49,18 +49,13 @@ struct lfds700_misc_prng_state ps[NUM_MAX_ENB];
|
||||
struct lfds700_ringbuffer_element *dl_mac_config_array[NUM_MAX_ENB];
|
||||
struct lfds700_ringbuffer_state ringbuffer_state[NUM_MAX_ENB];
|
||||
|
||||
/* the slice config as kept in the underlying system */
|
||||
Protocol__FlexSliceConfig *slice_config[MAX_NUM_SLICES];
|
||||
/* a structure that keeps updates which will be reflected in slice_config later */
|
||||
Protocol__FlexSliceConfig *sc_update[MAX_NUM_SLICES];
|
||||
/* indicates whether sc_update contains new data */
|
||||
int perform_slice_config_update_count = 1;
|
||||
/* queue of incoming new UE<>slice association commands */
|
||||
Protocol__FlexUeConfig *ue_slice_assoc_update[MAX_NUM_SLICES];
|
||||
int n_ue_slice_assoc_updates = 0;
|
||||
/* mutex for sc_update: do not receive new config and write it at the same time */
|
||||
pthread_mutex_t sc_update_mtx = PTHREAD_MUTEX_INITIALIZER;
|
||||
/* Ringbuffer-related to slice configuration */
|
||||
struct lfds700_ringbuffer_element *slice_config_array[NUM_MAX_ENB];
|
||||
struct lfds700_ringbuffer_state slice_config_ringbuffer_state[NUM_MAX_ENB];
|
||||
|
||||
/* Ringbuffer-related to slice configuration */
|
||||
struct lfds700_ringbuffer_element *ue_assoc_array[NUM_MAX_ENB];
|
||||
struct lfds700_ringbuffer_state ue_assoc_ringbuffer_state[NUM_MAX_ENB];
|
||||
|
||||
int flexran_agent_mac_stats_reply_ue(mid_t mod_id,
|
||||
Protocol__FlexUeStatsReport **ue_report,
|
||||
@@ -1354,6 +1349,33 @@ void flexran_agent_init_mac_agent(mid_t mod_id) {
|
||||
AssertFatal(i == 0, "posix_memalign(): could not allocate aligned memory for lfds library\n");
|
||||
lfds700_ringbuffer_init_valid_on_current_logical_core(&ringbuffer_state[mod_id],
|
||||
dl_mac_config_array[mod_id], num_elements, &ps[mod_id], NULL);
|
||||
|
||||
struct lfds700_misc_prng_state scrng;
|
||||
i = posix_memalign((void **) &slice_config_array[mod_id],
|
||||
LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES,
|
||||
sizeof(struct lfds700_ringbuffer_element) * num_elements);
|
||||
AssertFatal(i == 0,
|
||||
"posix_memalign(): could not allocate aligned memory\n");
|
||||
lfds700_ringbuffer_init_valid_on_current_logical_core(
|
||||
&slice_config_ringbuffer_state[mod_id],
|
||||
slice_config_array[mod_id],
|
||||
num_elements,
|
||||
&scrng,
|
||||
NULL);
|
||||
|
||||
struct lfds700_misc_prng_state uarng;
|
||||
i = posix_memalign((void **) &ue_assoc_array[mod_id],
|
||||
LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES,
|
||||
sizeof(struct lfds700_ringbuffer_element) * num_elements);
|
||||
AssertFatal(i == 0,
|
||||
"posix_memalign(): could not allocate aligned memory\n");
|
||||
lfds700_ringbuffer_init_valid_on_current_logical_core(
|
||||
&ue_assoc_ringbuffer_state[mod_id],
|
||||
ue_assoc_array[mod_id],
|
||||
num_elements,
|
||||
&uarng,
|
||||
NULL);
|
||||
|
||||
for (i = 0; i < MAX_MOBILES_PER_ENB; i++) {
|
||||
for (j = 0; j < 8; j++) {
|
||||
if (RC.mac && RC.mac[mod_id])
|
||||
@@ -1465,9 +1487,74 @@ void flexran_agent_fill_mac_cell_config(mid_t mod_id, uint8_t cc_id,
|
||||
conf->si_config->has_sfn = 1;
|
||||
}
|
||||
|
||||
/* get a pointer to the config which is maintained in the agent throughout
|
||||
* its lifetime */
|
||||
conf->slice_config = flexran_agent_get_slice_config(mod_id);
|
||||
conf->slice_config = malloc(sizeof(Protocol__FlexSliceConfig));
|
||||
if (conf->slice_config) {
|
||||
protocol__flex_slice_config__init(conf->slice_config);
|
||||
Protocol__FlexSliceConfig *sc = conf->slice_config;
|
||||
|
||||
sc->dl = malloc(sizeof(Protocol__FlexSliceDlUlConfig));
|
||||
DevAssert(sc->dl);
|
||||
protocol__flex_slice_dl_ul_config__init(sc->dl);
|
||||
sc->dl->algorithm = flexran_get_dl_slice_algo(mod_id);
|
||||
sc->dl->has_algorithm = 1;
|
||||
sc->dl->n_slices = flexran_get_num_dl_slices(mod_id);
|
||||
if (sc->dl->n_slices > 0) {
|
||||
sc->dl->slices = calloc(sc->dl->n_slices, sizeof(Protocol__FlexSlice *));
|
||||
DevAssert(sc->dl->slices);
|
||||
for (int i = 0; i < sc->dl->n_slices; ++i) {
|
||||
sc->dl->slices[i] = malloc(sizeof(Protocol__FlexSlice));
|
||||
DevAssert(sc->dl->slices[i]);
|
||||
protocol__flex_slice__init(sc->dl->slices[i]);
|
||||
flexran_get_dl_slice(mod_id, i, sc->dl->slices[i], sc->dl->algorithm);
|
||||
}
|
||||
} else {
|
||||
sc->dl->scheduler = flexran_get_dl_scheduler_name(mod_id);
|
||||
}
|
||||
|
||||
sc->ul = malloc(sizeof(Protocol__FlexSliceDlUlConfig));
|
||||
DevAssert(sc->ul);
|
||||
protocol__flex_slice_dl_ul_config__init(sc->ul);
|
||||
sc->ul->algorithm = flexran_get_ul_slice_algo(mod_id);
|
||||
sc->ul->has_algorithm = 1;
|
||||
sc->ul->n_slices = flexran_get_num_ul_slices(mod_id);
|
||||
if (sc->ul->n_slices > 0) {
|
||||
sc->ul->slices = calloc(sc->ul->n_slices, sizeof(Protocol__FlexSlice *));
|
||||
DevAssert(sc->ul->slices);
|
||||
for (int i = 0; i < sc->ul->n_slices; ++i) {
|
||||
sc->ul->slices[i] = malloc(sizeof(Protocol__FlexSlice));
|
||||
DevAssert(sc->ul->slices[i]);
|
||||
protocol__flex_slice__init(sc->ul->slices[i]);
|
||||
flexran_get_ul_slice(mod_id, i, sc->ul->slices[i], sc->ul->algorithm);
|
||||
}
|
||||
} else {
|
||||
sc->ul->scheduler = flexran_get_ul_scheduler_name(mod_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void flexran_agent_destroy_mac_slice_config(Protocol__FlexCellConfig *conf) {
|
||||
Protocol__FlexSliceConfig *sc = conf->slice_config;
|
||||
for (int i = 0; i < sc->dl->n_slices; ++i) {
|
||||
free(sc->dl->slices[i]);
|
||||
sc->dl->slices[i] = NULL;
|
||||
/* scheduler names are not freed: we assume we read them directly from the
|
||||
* underlying memory and do not dispose it */
|
||||
}
|
||||
free(sc->dl->slices);
|
||||
/* scheduler name is not freed */
|
||||
free(sc->dl);
|
||||
sc->dl = NULL;
|
||||
for (int i = 0; i < sc->ul->n_slices; ++i) {
|
||||
free(sc->ul->slices[i]);
|
||||
sc->ul->slices[i] = NULL;
|
||||
/* scheduler names are not freed */
|
||||
}
|
||||
free(sc->ul->slices);
|
||||
/* scheduler name is not freed */
|
||||
free(sc->ul);
|
||||
sc->ul = NULL;
|
||||
free(conf->slice_config);
|
||||
conf->slice_config = NULL;
|
||||
}
|
||||
|
||||
void flexran_agent_fill_mac_ue_config(mid_t mod_id, mid_t ue_id,
|
||||
@@ -1481,10 +1568,12 @@ void flexran_agent_fill_mac_ue_config(mid_t mod_id, mid_t ue_id,
|
||||
ue_conf->rnti = flexran_get_mac_ue_crnti(mod_id, ue_id);
|
||||
ue_conf->has_rnti = 1;
|
||||
|
||||
ue_conf->dl_slice_id = flexran_get_ue_dl_slice_id(mod_id, ue_id);
|
||||
ue_conf->has_dl_slice_id = 1;
|
||||
ue_conf->ul_slice_id = flexran_get_ue_ul_slice_id(mod_id, ue_id);
|
||||
ue_conf->has_ul_slice_id = 1;
|
||||
int dl_id = flexran_get_ue_dl_slice_id(mod_id, ue_id);
|
||||
ue_conf->dl_slice_id = dl_id;
|
||||
ue_conf->has_dl_slice_id = dl_id >= 0;
|
||||
int ul_id = flexran_get_ue_ul_slice_id(mod_id, ue_id);
|
||||
ue_conf->ul_slice_id = ul_id;
|
||||
ue_conf->has_ul_slice_id = ul_id >= 0;
|
||||
|
||||
ue_conf->ue_aggregated_max_bitrate_ul = flexran_get_ue_aggregated_max_bitrate_ul(mod_id, ue_id);
|
||||
ue_conf->has_ue_aggregated_max_bitrate_ul = 1;
|
||||
@@ -1565,6 +1654,15 @@ int flexran_agent_unregister_mac_xface(mid_t mod_id)
|
||||
LOG_E(FLEXRAN_AGENT, "MAC agent CM for eNB %d is not registered\n", mod_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
lfds700_ringbuffer_cleanup(&ringbuffer_state[mod_id], NULL );
|
||||
free(dl_mac_config_array[mod_id]);
|
||||
lfds700_ringbuffer_cleanup(&slice_config_ringbuffer_state[mod_id], NULL );
|
||||
free(slice_config_array[mod_id]);
|
||||
lfds700_ringbuffer_cleanup(&ue_assoc_ringbuffer_state[mod_id], NULL );
|
||||
free(ue_assoc_array[mod_id]);
|
||||
lfds700_misc_library_cleanup();
|
||||
|
||||
AGENT_MAC_xface *xface = agent_mac_xface[mod_id];
|
||||
xface->flexran_agent_send_sr_info = NULL;
|
||||
xface->flexran_agent_send_sf_trigger = NULL;
|
||||
@@ -1579,230 +1677,91 @@ int flexran_agent_unregister_mac_xface(mid_t mod_id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void flexran_create_config_structures(mid_t mod_id)
|
||||
{
|
||||
int i;
|
||||
int n_dl = flexran_get_num_dl_slices(mod_id);
|
||||
int m_ul = flexran_get_num_ul_slices(mod_id);
|
||||
slice_config[mod_id] = flexran_agent_create_slice_config(n_dl, m_ul);
|
||||
sc_update[mod_id] = flexran_agent_create_slice_config(n_dl, m_ul);
|
||||
if (!slice_config[mod_id] || !sc_update[mod_id]) return;
|
||||
|
||||
flexran_agent_read_slice_config(mod_id, slice_config[mod_id]);
|
||||
flexran_agent_read_slice_config(mod_id, sc_update[mod_id]);
|
||||
for (i = 0; i < n_dl; i++) {
|
||||
flexran_agent_read_slice_dl_config(mod_id, i, slice_config[mod_id]->dl[i]);
|
||||
flexran_agent_read_slice_dl_config(mod_id, i, sc_update[mod_id]->dl[i]);
|
||||
void helper_destroy_mac_slice_config(Protocol__FlexSliceConfig *slice_config) {
|
||||
if (slice_config->dl) {
|
||||
if (slice_config->dl->scheduler)
|
||||
free(slice_config->dl->scheduler);
|
||||
for (int i = 0; i < slice_config->dl->n_slices; i++)
|
||||
if (slice_config->dl->slices[i]->scheduler)
|
||||
free(slice_config->dl->slices[i]->scheduler);
|
||||
}
|
||||
for (i = 0; i < m_ul; i++) {
|
||||
flexran_agent_read_slice_ul_config(mod_id, i, slice_config[mod_id]->ul[i]);
|
||||
flexran_agent_read_slice_ul_config(mod_id, i, sc_update[mod_id]->ul[i]);
|
||||
if (slice_config->ul) {
|
||||
if (slice_config->ul->scheduler)
|
||||
free(slice_config->ul->scheduler);
|
||||
for (int i = 0; i < slice_config->ul->n_slices; i++)
|
||||
if (slice_config->ul->slices[i]->scheduler)
|
||||
free(slice_config->ul->slices[i]->scheduler);
|
||||
}
|
||||
|
||||
Protocol__FlexCellConfig helper;
|
||||
helper.slice_config = slice_config;
|
||||
flexran_agent_destroy_mac_slice_config(&helper);
|
||||
}
|
||||
|
||||
void prepare_update_slice_config(mid_t mod_id, Protocol__FlexSliceConfig **slice_config) {
|
||||
if (!*slice_config) return;
|
||||
/* just use the memory and set to NULL in original */
|
||||
Protocol__FlexSliceConfig *sc = *slice_config;
|
||||
*slice_config = NULL;
|
||||
|
||||
struct lfds700_misc_prng_state ls;
|
||||
LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE;
|
||||
lfds700_misc_prng_init(&ls);
|
||||
enum lfds700_misc_flag overwrite_occurred_flag;
|
||||
|
||||
Protocol__FlexSliceConfig *overwritten_sc;
|
||||
lfds700_ringbuffer_write(&slice_config_ringbuffer_state[mod_id],
|
||||
NULL,
|
||||
(void *)sc,
|
||||
&overwrite_occurred_flag,
|
||||
NULL,
|
||||
(void **)&overwritten_sc,
|
||||
&ls);
|
||||
|
||||
if (overwrite_occurred_flag == LFDS700_MISC_FLAG_RAISED) {
|
||||
helper_destroy_mac_slice_config(overwritten_sc);
|
||||
LOG_E(FLEXRAN_AGENT, "lost slice config: too many reconfigurations at once\n");
|
||||
}
|
||||
}
|
||||
|
||||
void flexran_check_and_remove_slices(mid_t mod_id)
|
||||
{
|
||||
Protocol__FlexDlSlice **dl = sc_update[mod_id]->dl;
|
||||
Protocol__FlexDlSlice **dlreal = slice_config[mod_id]->dl;
|
||||
int i = 0;
|
||||
while (i < sc_update[mod_id]->n_dl) {
|
||||
/* remove slices whose percentage is zero */
|
||||
if (dl[i]->percentage > 0) {
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
if (flexran_remove_dl_slice(mod_id, i) < 1) {
|
||||
LOG_W(FLEXRAN_AGENT, "[%d] can not remove slice index %d ID %d\n",
|
||||
mod_id, i, dl[i]->id);
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
LOG_I(FLEXRAN_AGENT, "[%d] removed slice index %d ID %d\n",
|
||||
mod_id, i, dl[i]->id);
|
||||
if (dl[i]->n_sorting > 0) free(dl[i]->sorting);
|
||||
free(dl[i]->scheduler_name);
|
||||
if (dlreal[i]->n_sorting > 0) {
|
||||
dlreal[i]->n_sorting = 0;
|
||||
free(dlreal[i]->sorting);
|
||||
}
|
||||
free(dlreal[i]->scheduler_name);
|
||||
--sc_update[mod_id]->n_dl;
|
||||
--slice_config[mod_id]->n_dl;
|
||||
const size_t last = sc_update[mod_id]->n_dl;
|
||||
/* we need to memcpy the higher slice to the position we just deleted */
|
||||
memcpy(dl[i], dl[last], sizeof(*dl[last]));
|
||||
memset(dl[last], 0, sizeof(*dl[last]));
|
||||
memcpy(dlreal[i], dlreal[last], sizeof(*dlreal[last]));
|
||||
memset(dlreal[last], 0, sizeof(*dlreal[last]));
|
||||
/* dont increase i but recheck the slice which has been copied to here */
|
||||
}
|
||||
Protocol__FlexUlSlice **ul = sc_update[mod_id]->ul;
|
||||
Protocol__FlexUlSlice **ulreal = slice_config[mod_id]->ul;
|
||||
i = 0;
|
||||
while (i < sc_update[mod_id]->n_ul) {
|
||||
if (ul[i]->percentage > 0) {
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
if (flexran_remove_ul_slice(mod_id, i) < 1) {
|
||||
LOG_W(FLEXRAN_AGENT, "[%d] can not remove slice index %d ID %d\n",
|
||||
mod_id, i, ul[i]->id);
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
LOG_I(FLEXRAN_AGENT, "[%d] removed slice index %d ID %d\n",
|
||||
mod_id, i, ul[i]->id);
|
||||
free(ul[i]->scheduler_name);
|
||||
free(ulreal[i]->scheduler_name);
|
||||
--sc_update[mod_id]->n_ul;
|
||||
--slice_config[mod_id]->n_ul;
|
||||
const size_t last = sc_update[mod_id]->n_ul;
|
||||
/* see DL remarks */
|
||||
memcpy(ul[i], ul[last], sizeof(*ul[last]));
|
||||
memset(ul[last], 0, sizeof(*ul[last]));
|
||||
memcpy(ulreal[i], ulreal[last], sizeof(*ulreal[last]));
|
||||
memset(ulreal[last], 0, sizeof(*ulreal[last]));
|
||||
/* dont increase i but recheck the slice which has been copied to here */
|
||||
void prepare_ue_slice_assoc_update(mid_t mod_id, Protocol__FlexUeConfig **ue_config) {
|
||||
struct lfds700_misc_prng_state ls;
|
||||
LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE;
|
||||
lfds700_misc_prng_init(&ls);
|
||||
enum lfds700_misc_flag overwrite_occurred_flag;
|
||||
|
||||
Protocol__FlexUeConfig *overwritten_ue_config;
|
||||
lfds700_ringbuffer_write(&ue_assoc_ringbuffer_state[mod_id],
|
||||
NULL,
|
||||
(void *) *ue_config,
|
||||
&overwrite_occurred_flag,
|
||||
NULL,
|
||||
(void **)&overwritten_ue_config,
|
||||
&ls);
|
||||
|
||||
if (overwrite_occurred_flag == LFDS700_MISC_FLAG_RAISED) {
|
||||
free(overwritten_ue_config);
|
||||
LOG_E(FLEXRAN_AGENT, "lost UE-slice association: too many UE-slice associations at once\n");
|
||||
}
|
||||
}
|
||||
|
||||
void flexran_agent_slice_update(mid_t mod_id)
|
||||
{
|
||||
int i;
|
||||
int changes = 0;
|
||||
void flexran_agent_slice_update(mid_t mod_id) {
|
||||
struct lfds700_misc_prng_state ls;
|
||||
LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE;
|
||||
lfds700_misc_prng_init(&ls);
|
||||
|
||||
if (perform_slice_config_update_count <= 0) return;
|
||||
perform_slice_config_update_count--;
|
||||
|
||||
pthread_mutex_lock(&sc_update_mtx);
|
||||
|
||||
if (!slice_config[mod_id]) {
|
||||
/* if the configuration does not exist for agent, create from eNB structure
|
||||
* and exit */
|
||||
flexran_create_config_structures(mod_id);
|
||||
pthread_mutex_unlock(&sc_update_mtx);
|
||||
return;
|
||||
Protocol__FlexSliceConfig *sc = NULL;
|
||||
struct lfds700_ringbuffer_state *state = &slice_config_ringbuffer_state[mod_id];
|
||||
if (lfds700_ringbuffer_read(state, NULL, (void **) &sc, &ls) != 0) {
|
||||
apply_update_dl_slice_config(mod_id, sc->dl);
|
||||
apply_update_ul_slice_config(mod_id, sc->ul);
|
||||
helper_destroy_mac_slice_config(sc);
|
||||
}
|
||||
|
||||
/********* read existing config *********/
|
||||
/* simply update slice_config all the time and write new config
|
||||
* (apply_new_slice_dl_config() only updates if changes are necessary) */
|
||||
slice_config[mod_id]->n_dl = flexran_get_num_dl_slices(mod_id);
|
||||
slice_config[mod_id]->n_ul = flexran_get_num_ul_slices(mod_id);
|
||||
for (i = 0; i < slice_config[mod_id]->n_dl; i++) {
|
||||
flexran_agent_read_slice_dl_config(mod_id, i, slice_config[mod_id]->dl[i]);
|
||||
Protocol__FlexUeConfig *ue_config = NULL;
|
||||
state = &ue_assoc_ringbuffer_state[mod_id];
|
||||
if (lfds700_ringbuffer_read(state, NULL, (void **) &ue_config, &ls) != 0) {
|
||||
apply_ue_slice_assoc_update(mod_id, ue_config);
|
||||
free(ue_config);
|
||||
}
|
||||
for (i = 0; i < slice_config[mod_id]->n_ul; i++) {
|
||||
flexran_agent_read_slice_ul_config(mod_id, i, slice_config[mod_id]->ul[i]);
|
||||
}
|
||||
|
||||
/********* write new config *********/
|
||||
/* check for removal (sc_update[X]->dl[Y].percentage == 0)
|
||||
* and update sc_update & slice_config accordingly */
|
||||
flexran_check_and_remove_slices(mod_id);
|
||||
|
||||
/* create new DL and UL slices if necessary */
|
||||
for (i = slice_config[mod_id]->n_dl; i < sc_update[mod_id]->n_dl; i++) {
|
||||
flexran_create_dl_slice(mod_id, sc_update[mod_id]->dl[i]->id);
|
||||
}
|
||||
for (i = slice_config[mod_id]->n_ul; i < sc_update[mod_id]->n_ul; i++) {
|
||||
flexran_create_ul_slice(mod_id, sc_update[mod_id]->ul[i]->id);
|
||||
}
|
||||
slice_config[mod_id]->n_dl = flexran_get_num_dl_slices(mod_id);
|
||||
slice_config[mod_id]->n_ul = flexran_get_num_ul_slices(mod_id);
|
||||
changes += apply_new_slice_config(mod_id, slice_config[mod_id], sc_update[mod_id]);
|
||||
for (i = 0; i < slice_config[mod_id]->n_dl; i++) {
|
||||
changes += apply_new_slice_dl_config(mod_id,
|
||||
slice_config[mod_id]->dl[i],
|
||||
sc_update[mod_id]->dl[i]);
|
||||
flexran_agent_read_slice_dl_config(mod_id, i, slice_config[mod_id]->dl[i]);
|
||||
}
|
||||
for (i = 0; i < slice_config[mod_id]->n_ul; i++) {
|
||||
changes += apply_new_slice_ul_config(mod_id,
|
||||
slice_config[mod_id]->ul[i],
|
||||
sc_update[mod_id]->ul[i]);
|
||||
flexran_agent_read_slice_ul_config(mod_id, i, slice_config[mod_id]->ul[i]);
|
||||
}
|
||||
flexran_agent_read_slice_config(mod_id, slice_config[mod_id]);
|
||||
if (n_ue_slice_assoc_updates > 0) {
|
||||
changes += apply_ue_slice_assoc_update(mod_id);
|
||||
}
|
||||
if (changes > 0)
|
||||
LOG_I(FLEXRAN_AGENT, "[%d] slice configuration: applied %d changes\n", mod_id, changes);
|
||||
|
||||
pthread_mutex_unlock(&sc_update_mtx);
|
||||
}
|
||||
|
||||
Protocol__FlexSliceConfig *flexran_agent_get_slice_config(mid_t mod_id)
|
||||
{
|
||||
if (!slice_config[mod_id]) return NULL;
|
||||
Protocol__FlexSliceConfig *config = NULL;
|
||||
|
||||
pthread_mutex_lock(&sc_update_mtx);
|
||||
config = flexran_agent_create_slice_config(slice_config[mod_id]->n_dl,
|
||||
slice_config[mod_id]->n_ul);
|
||||
if (!config) {
|
||||
pthread_mutex_unlock(&sc_update_mtx);
|
||||
return NULL;
|
||||
}
|
||||
config->has_intraslice_share_active = 1;
|
||||
config->intraslice_share_active = slice_config[mod_id]->intraslice_share_active;
|
||||
config->has_interslice_share_active = 1;
|
||||
config->interslice_share_active = slice_config[mod_id]->interslice_share_active;
|
||||
for (int i = 0; i < slice_config[mod_id]->n_dl; ++i) {
|
||||
if (!config->dl[i]) continue;
|
||||
config->dl[i]->has_id = 1;
|
||||
config->dl[i]->id = slice_config[mod_id]->dl[i]->id;
|
||||
config->dl[i]->has_label = 1;
|
||||
config->dl[i]->label = slice_config[mod_id]->dl[i]->label;
|
||||
config->dl[i]->has_percentage = 1;
|
||||
config->dl[i]->percentage = slice_config[mod_id]->dl[i]->percentage;
|
||||
config->dl[i]->has_isolation = 1;
|
||||
config->dl[i]->isolation = slice_config[mod_id]->dl[i]->isolation;
|
||||
config->dl[i]->has_priority = 1;
|
||||
config->dl[i]->priority = slice_config[mod_id]->dl[i]->priority;
|
||||
config->dl[i]->has_position_low = 1;
|
||||
config->dl[i]->position_low = slice_config[mod_id]->dl[i]->position_low;
|
||||
config->dl[i]->has_position_high = 1;
|
||||
config->dl[i]->position_high = slice_config[mod_id]->dl[i]->position_high;
|
||||
config->dl[i]->has_maxmcs = 1;
|
||||
config->dl[i]->maxmcs = slice_config[mod_id]->dl[i]->maxmcs;
|
||||
config->dl[i]->n_sorting = slice_config[mod_id]->dl[i]->n_sorting;
|
||||
config->dl[i]->sorting = calloc(config->dl[i]->n_sorting, sizeof(Protocol__FlexDlSorting));
|
||||
if (!config->dl[i]->sorting) config->dl[i]->n_sorting = 0;
|
||||
for (int j = 0; j < config->dl[i]->n_sorting; ++j)
|
||||
config->dl[i]->sorting[j] = slice_config[mod_id]->dl[i]->sorting[j];
|
||||
config->dl[i]->has_accounting = 1;
|
||||
config->dl[i]->accounting = slice_config[mod_id]->dl[i]->accounting;
|
||||
config->dl[i]->scheduler_name = strdup(slice_config[mod_id]->dl[i]->scheduler_name);
|
||||
}
|
||||
for (int i = 0; i < slice_config[mod_id]->n_ul; ++i) {
|
||||
if (!config->ul[i]) continue;
|
||||
config->ul[i]->has_id = 1;
|
||||
config->ul[i]->id = slice_config[mod_id]->ul[i]->id;
|
||||
config->ul[i]->has_label = 1;
|
||||
config->ul[i]->label = slice_config[mod_id]->ul[i]->label;
|
||||
config->ul[i]->has_percentage = 1;
|
||||
config->ul[i]->percentage = slice_config[mod_id]->ul[i]->percentage;
|
||||
config->ul[i]->has_isolation = 1;
|
||||
config->ul[i]->isolation = slice_config[mod_id]->ul[i]->isolation;
|
||||
config->ul[i]->has_priority = 1;
|
||||
config->ul[i]->priority = slice_config[mod_id]->ul[i]->priority;
|
||||
config->ul[i]->has_first_rb = 1;
|
||||
config->ul[i]->first_rb = slice_config[mod_id]->ul[i]->first_rb;
|
||||
config->ul[i]->has_maxmcs = 1;
|
||||
config->ul[i]->maxmcs = slice_config[mod_id]->ul[i]->maxmcs;
|
||||
config->ul[i]->n_sorting = slice_config[mod_id]->ul[i]->n_sorting;
|
||||
config->ul[i]->sorting = calloc(config->ul[i]->n_sorting, sizeof(Protocol__FlexUlSorting));
|
||||
if (!config->ul[i]->sorting) config->ul[i]->n_sorting = 0;
|
||||
for (int j = 0; j < config->ul[i]->n_sorting; ++j)
|
||||
config->ul[i]->sorting[j] = slice_config[mod_id]->ul[i]->sorting[j];
|
||||
config->ul[i]->has_accounting = 1;
|
||||
config->ul[i]->accounting = slice_config[mod_id]->ul[i]->accounting;
|
||||
config->ul[i]->scheduler_name = strdup(slice_config[mod_id]->ul[i]->scheduler_name);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&sc_update_mtx);
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -115,7 +115,16 @@ int flexran_agent_unregister_mac_xface(mid_t mod_id);
|
||||
/* Inform controller about possibility to update slice configuration */
|
||||
void flexran_agent_slice_update(mid_t mod_id);
|
||||
|
||||
/* return a pointer to the current config */
|
||||
Protocol__FlexSliceConfig *flexran_agent_get_slice_config(mid_t mod_id);
|
||||
/* marks slice_config so that it can be applied later. Takes ownership of the
|
||||
* FlexSliceConfig message */
|
||||
void prepare_update_slice_config(mid_t mod_id, Protocol__FlexSliceConfig **slice);
|
||||
|
||||
/* inserts a new ue_config into the structure keeping ue to slice association
|
||||
* updates and marks so it can be applied. Takes ownership of the FlexUeConfig message */
|
||||
void prepare_ue_slice_assoc_update(mid_t mod_id, Protocol__FlexUeConfig **ue_config);
|
||||
|
||||
/* free slice_config part of flexCellConfig, filled in
|
||||
* flexran_agent_fill_mac_cell_config() */
|
||||
void flexran_agent_destroy_mac_slice_config(Protocol__FlexCellConfig *conf);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -33,14 +33,6 @@
|
||||
#include "flexran_agent_mac_internal.h"
|
||||
#include "flexran_agent_mac_slice_verification.h"
|
||||
|
||||
/* from flexran_agent_mac.c */
|
||||
extern Protocol__FlexSliceConfig *slice_config[MAX_NUM_SLICES];
|
||||
extern Protocol__FlexSliceConfig *sc_update[MAX_NUM_SLICES];
|
||||
extern int perform_slice_config_update_count;
|
||||
extern Protocol__FlexUeConfig *ue_slice_assoc_update[MAX_NUM_SLICES];
|
||||
extern int n_ue_slice_assoc_updates;
|
||||
extern pthread_mutex_t sc_update_mtx;
|
||||
|
||||
Protocol__FlexranMessage * flexran_agent_generate_diff_mac_stats_report(Protocol__FlexranMessage *new_message,
|
||||
Protocol__FlexranMessage *old_message) {
|
||||
|
||||
@@ -1033,724 +1025,166 @@ int load_dl_scheduler_function(mid_t mod_id, const char *function_name) {
|
||||
|
||||
}
|
||||
|
||||
Protocol__FlexSliceConfig *flexran_agent_create_slice_config(int n_dl, int m_ul)
|
||||
{
|
||||
int i;
|
||||
Protocol__FlexSliceConfig *fsc = malloc(sizeof(Protocol__FlexSliceConfig));
|
||||
if (!fsc) return NULL;
|
||||
protocol__flex_slice_config__init(fsc);
|
||||
|
||||
/* say there are n_dl slices but reserve memory for up to MAX_NUM_SLICES so
|
||||
* we don't need to reserve again later */
|
||||
fsc->n_dl = n_dl;
|
||||
fsc->dl = calloc(MAX_NUM_SLICES, sizeof(Protocol__FlexDlSlice *));
|
||||
if (!fsc->dl) fsc->n_dl = 0;
|
||||
for (i = 0; i < MAX_NUM_SLICES; i++) {
|
||||
fsc->dl[i] = malloc(sizeof(Protocol__FlexDlSlice));
|
||||
if (!fsc->dl[i]) continue;
|
||||
protocol__flex_dl_slice__init(fsc->dl[i]);
|
||||
}
|
||||
|
||||
/* as above */
|
||||
fsc->n_ul = m_ul;
|
||||
fsc->ul = calloc(MAX_NUM_SLICES, sizeof(Protocol__FlexUlSlice *));
|
||||
if (!fsc->ul) fsc->n_ul = 0;
|
||||
for (i = 0; i < MAX_NUM_SLICES; i++) {
|
||||
fsc->ul[i] = malloc(sizeof(Protocol__FlexUlSlice));
|
||||
if (!fsc->ul[i]) continue;
|
||||
protocol__flex_ul_slice__init(fsc->ul[i]);
|
||||
}
|
||||
return fsc;
|
||||
}
|
||||
|
||||
void flexran_agent_read_slice_config(mid_t mod_id, Protocol__FlexSliceConfig *s)
|
||||
{
|
||||
s->intraslice_share_active = flexran_get_intraslice_sharing_active(mod_id);
|
||||
s->has_intraslice_share_active = 1;
|
||||
s->interslice_share_active = flexran_get_interslice_sharing_active(mod_id);
|
||||
s->has_interslice_share_active = 1;
|
||||
}
|
||||
|
||||
void flexran_agent_read_slice_dl_config(mid_t mod_id, int slice_idx, Protocol__FlexDlSlice *dl_slice)
|
||||
{
|
||||
dl_slice->id = flexran_get_dl_slice_id(mod_id, slice_idx);
|
||||
dl_slice->has_id = 1;
|
||||
/* read label from corresponding sc_update entry or give default */
|
||||
dl_slice->label = PROTOCOL__FLEX_SLICE_LABEL__xMBB;
|
||||
dl_slice->has_label = 1;
|
||||
for (int i = 0; i < sc_update[mod_id]->n_dl; i++) {
|
||||
if (sc_update[mod_id]->dl[i]->id == dl_slice->id
|
||||
&& sc_update[mod_id]->dl[i]->has_label) {
|
||||
dl_slice->label = sc_update[mod_id]->dl[i]->label;
|
||||
break;
|
||||
}
|
||||
}
|
||||
dl_slice->percentage = flexran_get_dl_slice_percentage(mod_id, slice_idx);
|
||||
dl_slice->has_percentage = 1;
|
||||
dl_slice->isolation = flexran_get_dl_slice_isolation(mod_id, slice_idx);
|
||||
dl_slice->has_isolation = 1;
|
||||
dl_slice->priority = flexran_get_dl_slice_priority(mod_id, slice_idx);
|
||||
dl_slice->has_priority = 1;
|
||||
dl_slice->position_low = flexran_get_dl_slice_position_low(mod_id, slice_idx);
|
||||
dl_slice->has_position_low = 1;
|
||||
dl_slice->position_high = flexran_get_dl_slice_position_high(mod_id, slice_idx);
|
||||
dl_slice->has_position_high = 1;
|
||||
dl_slice->maxmcs = flexran_get_dl_slice_maxmcs(mod_id, slice_idx);
|
||||
dl_slice->has_maxmcs = 1;
|
||||
dl_slice->n_sorting = flexran_get_dl_slice_sorting(mod_id, slice_idx, &dl_slice->sorting);
|
||||
if (dl_slice->n_sorting < 1) dl_slice->sorting = NULL;
|
||||
dl_slice->accounting = flexran_get_dl_slice_accounting_policy(mod_id, slice_idx);
|
||||
dl_slice->has_accounting = 1;
|
||||
const char *s_name = flexran_get_dl_slice_scheduler(mod_id, slice_idx);
|
||||
if (!dl_slice->scheduler_name
|
||||
|| strcmp(dl_slice->scheduler_name, s_name) != 0) {
|
||||
dl_slice->scheduler_name = realloc(dl_slice->scheduler_name, strlen(s_name) + 1);
|
||||
strcpy(dl_slice->scheduler_name, s_name);
|
||||
}
|
||||
}
|
||||
|
||||
void flexran_agent_read_slice_ul_config(mid_t mod_id, int slice_idx, Protocol__FlexUlSlice *ul_slice)
|
||||
{
|
||||
ul_slice->id = flexran_get_ul_slice_id(mod_id, slice_idx);
|
||||
ul_slice->has_id = 1;
|
||||
/* read label from corresponding sc_update entry or give default */
|
||||
ul_slice->label = PROTOCOL__FLEX_SLICE_LABEL__xMBB;
|
||||
ul_slice->has_label = 1;
|
||||
for (int i = 0; i < sc_update[mod_id]->n_ul; i++) {
|
||||
if (sc_update[mod_id]->ul[i]->id == ul_slice->id
|
||||
&& sc_update[mod_id]->ul[i]->has_label) {
|
||||
ul_slice->label = sc_update[mod_id]->ul[i]->label;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ul_slice->percentage = flexran_get_ul_slice_percentage(mod_id, slice_idx);
|
||||
ul_slice->has_percentage = 1;
|
||||
/*ul_slice->isolation = flexran_get_ul_slice_isolation(mod_id, slice_idx);*/
|
||||
ul_slice->has_isolation = 0;
|
||||
/*ul_slice->priority = flexran_get_ul_slice_priority(mod_id, slice_idx);*/
|
||||
ul_slice->has_priority = 0;
|
||||
ul_slice->first_rb = flexran_get_ul_slice_first_rb(mod_id, slice_idx);
|
||||
ul_slice->has_first_rb = 1;
|
||||
/*ul_slice-> = flexran_get_ul_slice_length_rb(mod_id, slice_idx);
|
||||
ul_slice->has_length_rb = 0;*/
|
||||
ul_slice->maxmcs = flexran_get_ul_slice_maxmcs(mod_id, slice_idx);
|
||||
ul_slice->has_maxmcs = 1;
|
||||
ul_slice->n_sorting = 0;
|
||||
/*if (ul_slice->sorting) {
|
||||
free(ul_slice->sorting);
|
||||
ul_slice->sorting = NULL;
|
||||
}
|
||||
ul_slice->n_sorting = flexran_get_ul_slice_sorting(mod_id, slice_idx, &ul_slice->sorting);
|
||||
if (ul_slice->n_sorting < 1) ul_slice->sorting = NULL;*/
|
||||
/*ul_slice->accounting = flexran_get_ul_slice_accounting_policy(mod_id, slice_idx);*/
|
||||
ul_slice->has_accounting = 0;
|
||||
const char *s_name = flexran_get_ul_slice_scheduler(mod_id, slice_idx);
|
||||
if (!ul_slice->scheduler_name
|
||||
|| strcmp(ul_slice->scheduler_name, s_name) != 0) {
|
||||
ul_slice->scheduler_name = realloc(ul_slice->scheduler_name, strlen(s_name) + 1);
|
||||
strcpy(ul_slice->scheduler_name, s_name);
|
||||
}
|
||||
}
|
||||
|
||||
int check_dl_sorting_update(Protocol__FlexDlSlice *old, Protocol__FlexDlSlice *new)
|
||||
{
|
||||
/* sorting_update => true when old->n_sorting == 0 or different numbers of
|
||||
* elements; otherwise will check * element-wise */
|
||||
int sorting_update = old->n_sorting == 0 || (old->n_sorting != new->n_sorting);
|
||||
for (int i = 0; i < old->n_sorting && !sorting_update; ++i) {
|
||||
sorting_update = sorting_update || (new->sorting[i] != old->sorting[i]);
|
||||
}
|
||||
return sorting_update;
|
||||
}
|
||||
|
||||
int check_ul_sorting_update(Protocol__FlexUlSlice *old, Protocol__FlexUlSlice *new)
|
||||
{
|
||||
/* sorting_update => true when old->n_sorting == 0 or different numbers of
|
||||
* elements; otherwise will check * element-wise */
|
||||
int sorting_update = old->n_sorting == 0 || (old->n_sorting != new->n_sorting);
|
||||
for (int i = 0; i < old->n_sorting && !sorting_update; ++i) {
|
||||
sorting_update = sorting_update || (new->sorting[i] != old->sorting[i]);
|
||||
}
|
||||
return sorting_update;
|
||||
}
|
||||
|
||||
void overwrite_slice_config(mid_t mod_id, Protocol__FlexSliceConfig *exist, Protocol__FlexSliceConfig *update)
|
||||
{
|
||||
if (update->has_intraslice_share_active
|
||||
&& exist->intraslice_share_active != update->intraslice_share_active) {
|
||||
LOG_I(FLEXRAN_AGENT, "[%d] update intraslice_share_active: %d -> %d\n",
|
||||
mod_id, exist->intraslice_share_active, update->intraslice_share_active);
|
||||
exist->intraslice_share_active = update->intraslice_share_active;
|
||||
exist->has_intraslice_share_active = 1;
|
||||
}
|
||||
if (update->has_interslice_share_active
|
||||
&& exist->interslice_share_active != update->interslice_share_active) {
|
||||
LOG_I(FLEXRAN_AGENT, "[%d] update interslice_share_active: %d -> %d\n",
|
||||
mod_id, exist->interslice_share_active, update->interslice_share_active);
|
||||
exist->interslice_share_active = update->interslice_share_active;
|
||||
exist->has_interslice_share_active = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void overwrite_slice_config_dl(mid_t mod_id, Protocol__FlexDlSlice *exist, Protocol__FlexDlSlice *update)
|
||||
{
|
||||
if (update->label != exist->label) {
|
||||
LOG_I(FLEXRAN_AGENT, "[%d][DL slice %d] update label: %d -> %d\n",
|
||||
mod_id, update->id, exist->label, update->label);
|
||||
exist->label = update->label;
|
||||
exist->has_label = 1;
|
||||
}
|
||||
if (update->percentage != exist->percentage) {
|
||||
LOG_I(FLEXRAN_AGENT, "[%d][DL slice %d] update percentage: %d -> %d\n",
|
||||
mod_id, update->id, exist->percentage, update->percentage);
|
||||
exist->percentage = update->percentage;
|
||||
exist->has_percentage = 1;
|
||||
}
|
||||
if (update->isolation != exist->isolation) {
|
||||
LOG_I(FLEXRAN_AGENT, "[%d][DL slice %d] update isolation: %d -> %d\n",
|
||||
mod_id, update->id, exist->isolation, update->isolation);
|
||||
exist->isolation = update->isolation;
|
||||
exist->has_isolation = 1;
|
||||
}
|
||||
if (update->priority != exist->priority) {
|
||||
LOG_I(FLEXRAN_AGENT, "[%d][DL slice %d] update priority: %d -> %d\n",
|
||||
mod_id, update->id, exist->priority, update->priority);
|
||||
exist->priority = update->priority;
|
||||
exist->has_priority = 1;
|
||||
}
|
||||
if (update->position_low != exist->position_low) {
|
||||
LOG_I(FLEXRAN_AGENT, "[%d][DL slice %d] update position_low: %d -> %d\n",
|
||||
mod_id, update->id, exist->position_low, update->position_low);
|
||||
exist->position_low = update->position_low;
|
||||
exist->has_position_low = 1;
|
||||
}
|
||||
if (update->position_high != exist->position_high) {
|
||||
LOG_I(FLEXRAN_AGENT, "[%d][DL slice %d] update position_high: %d -> %d\n",
|
||||
mod_id, update->id, exist->position_high, update->position_high);
|
||||
exist->position_high = update->position_high;
|
||||
exist->has_position_high = 1;
|
||||
}
|
||||
if (update->maxmcs != exist->maxmcs) {
|
||||
LOG_I(FLEXRAN_AGENT, "[%d][DL slice %d] update maxmcs: %d -> %d\n",
|
||||
mod_id, update->id, exist->maxmcs, update->maxmcs);
|
||||
exist->maxmcs = update->maxmcs;
|
||||
exist->has_maxmcs = 1;
|
||||
}
|
||||
if (check_dl_sorting_update(exist, update)) {
|
||||
LOG_I(FLEXRAN_AGENT, "[%d][DL slice %d] update sorting array\n", mod_id, update->id);
|
||||
if (exist->n_sorting != update->n_sorting) {
|
||||
exist->n_sorting = update->n_sorting;
|
||||
exist->sorting = realloc(exist->sorting, exist->n_sorting * sizeof(Protocol__FlexDlSorting));
|
||||
if (!exist->sorting) exist->n_sorting = 0;
|
||||
}
|
||||
for (int i = 0; i < exist->n_sorting; i++)
|
||||
exist->sorting[i] = update->sorting[i];
|
||||
}
|
||||
if (update->accounting != exist->accounting) {
|
||||
LOG_I(FLEXRAN_AGENT, "[%d][DL slice %d] update accounting: %d -> %d\n",
|
||||
mod_id, update->id, exist->accounting, update->accounting);
|
||||
exist->accounting = update->accounting;
|
||||
exist->has_accounting = 1;
|
||||
}
|
||||
if (!exist->scheduler_name
|
||||
|| strcmp(update->scheduler_name, exist->scheduler_name) != 0) {
|
||||
LOG_I(FLEXRAN_AGENT, "[%d][DL slice %d] update scheduler: %s -> %s\n",
|
||||
mod_id, update->id, exist->scheduler_name, update->scheduler_name);
|
||||
if (exist->scheduler_name) free(exist->scheduler_name);
|
||||
exist->scheduler_name = strdup(update->scheduler_name);
|
||||
}
|
||||
}
|
||||
|
||||
void overwrite_slice_config_ul(mid_t mod_id, Protocol__FlexUlSlice *exist, Protocol__FlexUlSlice *update)
|
||||
{
|
||||
if (update->label != exist->label) {
|
||||
LOG_I(FLEXRAN_AGENT, "[%d][UL slice %d] update label: %d -> %d\n",
|
||||
mod_id, update->id, exist->label, update->label);
|
||||
exist->label = update->label;
|
||||
exist->has_label = 1;
|
||||
}
|
||||
if (update->percentage != exist->percentage) {
|
||||
LOG_I(FLEXRAN_AGENT, "[%d][UL slice %d] update percentage: %d -> %d\n",
|
||||
mod_id, update->id, exist->percentage, update->percentage);
|
||||
exist->percentage = update->percentage;
|
||||
exist->has_percentage = 1;
|
||||
}
|
||||
if (update->isolation != exist->isolation) {
|
||||
LOG_I(FLEXRAN_AGENT, "[%d][UL slice %d] update isolation: %d -> %d\n",
|
||||
mod_id, update->id, exist->isolation, update->isolation);
|
||||
exist->isolation = update->isolation;
|
||||
exist->has_isolation = 1;
|
||||
}
|
||||
if (update->priority != exist->priority) {
|
||||
LOG_I(FLEXRAN_AGENT, "[%d][UL slice %d] update priority: %d -> %d\n",
|
||||
mod_id, update->id, exist->priority, update->priority);
|
||||
exist->priority = update->priority;
|
||||
exist->has_priority = 1;
|
||||
}
|
||||
if (update->first_rb != exist->first_rb) {
|
||||
LOG_I(FLEXRAN_AGENT, "[%d][UL slice %d] update first_rb: %d -> %d\n",
|
||||
mod_id, update->id, exist->first_rb, update->first_rb);
|
||||
exist->first_rb = update ->first_rb;
|
||||
exist->has_first_rb = 1;
|
||||
}
|
||||
/*if (update->lenght_rb != exist->lenght_rb) {
|
||||
LOG_I(FLEXRAN_AGENT, "[%d][UL slice %d] update lenght_rb: %d -> %d\n",
|
||||
mod_id, update->id, exist->lenght_rb, update->lenght_rb);
|
||||
exist->lenght_rb = update->lenght_rb;
|
||||
}*/
|
||||
if (update->maxmcs != exist->maxmcs) {
|
||||
LOG_I(FLEXRAN_AGENT, "[%d][UL slice %d] update maxmcs: %d -> %d\n",
|
||||
mod_id, update->id, exist->maxmcs, update->maxmcs);
|
||||
exist->maxmcs = update->maxmcs;
|
||||
exist->has_maxmcs = 1;
|
||||
}
|
||||
/* TODO
|
||||
int sorting_update = 0;
|
||||
int n = min(exist->n_sorting, update->n_sorting);
|
||||
int i = 0;
|
||||
while (i < n && !sorting_update) {
|
||||
sorting_update = sorting_update || (update->sorting[i] != exist->sorting[i]);
|
||||
i++;
|
||||
}
|
||||
if (sorting_update) {
|
||||
LOG_I(FLEXRAN_AGENT, "[%d][UL slice %d] update sorting array\n", update->id, mod_id);
|
||||
if (exist->n_sorting != update->n_sorting)
|
||||
LOG_W(FLEXRAN_AGENT, "[%d][UL slice %d] only writing %d elements\n",
|
||||
mod_id, update->id, n);
|
||||
for (i = 0; i < n; i++)
|
||||
exist->sorting[i] = update->sorting[i];
|
||||
}
|
||||
*/
|
||||
if (update->accounting != exist->accounting) {
|
||||
LOG_I(FLEXRAN_AGENT, "[%d][UL slice %d] update accounting: %d -> %d\n",
|
||||
mod_id, update->id, exist->accounting, update->accounting);
|
||||
exist->accounting = update->accounting;
|
||||
exist->has_accounting = 1;
|
||||
}
|
||||
if (!exist->scheduler_name
|
||||
|| strcmp(update->scheduler_name, exist->scheduler_name) != 0) {
|
||||
LOG_I(FLEXRAN_AGENT, "[%d][UL slice %d] update scheduler: %s -> %s\n",
|
||||
mod_id, update->id, exist->scheduler_name, update->scheduler_name);
|
||||
if (exist->scheduler_name) free(exist->scheduler_name);
|
||||
exist->scheduler_name = strdup(update->scheduler_name);
|
||||
}
|
||||
}
|
||||
|
||||
void fill_dl_slice(mid_t mod_id, Protocol__FlexDlSlice *s, Protocol__FlexDlSlice *from)
|
||||
{
|
||||
/* function fills slice with information from another slice or with default
|
||||
* values (currently slice 0) if from is NULL */
|
||||
/* TODO fill the slice depending on the chosen label */
|
||||
if (!s->has_label) {
|
||||
s->has_label = 1;
|
||||
s->label = from ? from->label : sc_update[mod_id]->dl[0]->label;
|
||||
}
|
||||
if (!s->has_percentage) {
|
||||
s->has_percentage = 1;
|
||||
s->percentage = from ? from->percentage : sc_update[mod_id]->dl[0]->percentage;
|
||||
}
|
||||
if (!s->has_isolation) {
|
||||
s->has_isolation = 1;
|
||||
s->isolation = from ? from->isolation : sc_update[mod_id]->dl[0]->isolation;
|
||||
}
|
||||
if (!s->has_priority) {
|
||||
s->has_priority = 1;
|
||||
s->priority = from ? from->priority : sc_update[mod_id]->dl[0]->priority;
|
||||
}
|
||||
if (!s->has_position_low) {
|
||||
s->has_position_low = 1;
|
||||
s->position_low = from ? from->position_low : sc_update[mod_id]->dl[0]->position_low;
|
||||
}
|
||||
if (!s->has_position_high) {
|
||||
s->has_position_high = 1;
|
||||
s->position_high = from ? from->position_high : sc_update[mod_id]->dl[0]->position_high;
|
||||
}
|
||||
if (!s->has_maxmcs) {
|
||||
s->has_maxmcs = 1;
|
||||
s->maxmcs = from ? from->maxmcs : sc_update[mod_id]->dl[0]->maxmcs;
|
||||
}
|
||||
if (s->n_sorting == 0) {
|
||||
s->n_sorting = from ? from->n_sorting : sc_update[mod_id]->dl[0]->n_sorting;
|
||||
s->sorting = calloc(s->n_sorting, sizeof(Protocol__FlexDlSorting));
|
||||
if (!s->sorting) s->n_sorting = 0;
|
||||
for (int i = 0; i < s->n_sorting; ++i)
|
||||
s->sorting[i] = from ? from->sorting[i] : sc_update[0]->dl[0]->sorting[i];
|
||||
}
|
||||
if (!s->has_accounting) {
|
||||
s->accounting = from ? from->accounting : sc_update[mod_id]->dl[0]->accounting;
|
||||
}
|
||||
if (!s->scheduler_name) {
|
||||
s->scheduler_name = strdup(from ? from->scheduler_name : sc_update[mod_id]->dl[0]->scheduler_name);
|
||||
}
|
||||
}
|
||||
|
||||
Protocol__FlexDlSlice *get_existing_dl_slice(mid_t mod_id, int id)
|
||||
{
|
||||
for (int i = 0; i < sc_update[mod_id]->n_dl; ++i) {
|
||||
if (id == sc_update[mod_id]->dl[i]->id) {
|
||||
return sc_update[mod_id]->dl[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Protocol__FlexDlSlice *create_new_dl_slice(mid_t mod_id, int id)
|
||||
{
|
||||
LOG_I(FLEXRAN_AGENT,
|
||||
"[%d] Creating DL slice with ID %d, taking default values from DL slice 0\n",
|
||||
mod_id, id);
|
||||
Protocol__FlexDlSlice *to = sc_update[mod_id]->dl[sc_update[mod_id]->n_dl];
|
||||
sc_update[mod_id]->n_dl++;
|
||||
AssertFatal(sc_update[mod_id]->n_dl <= MAX_NUM_SLICES,
|
||||
"cannot create more than MAX_NUM_SLICES\n");
|
||||
to->id = id;
|
||||
return to;
|
||||
}
|
||||
|
||||
void fill_ul_slice(mid_t mod_id, Protocol__FlexUlSlice *s, Protocol__FlexUlSlice *from)
|
||||
{
|
||||
/* function fills slice with information from another slice or with default
|
||||
* values (currently slice 0) if from is NULL */
|
||||
/* TODO fill the slice depending on the chosen label */
|
||||
if (!s->has_label) {
|
||||
s->has_label = 1;
|
||||
s->label = from ? from->label : sc_update[mod_id]->ul[0]->label;
|
||||
}
|
||||
if (!s->has_percentage) {
|
||||
s->has_percentage = 1;
|
||||
s->percentage = from ? from->percentage : sc_update[mod_id]->ul[0]->percentage;
|
||||
}
|
||||
if (!s->has_isolation) {
|
||||
s->has_isolation = 1;
|
||||
s->isolation = from ? from->isolation : sc_update[mod_id]->ul[0]->isolation;
|
||||
}
|
||||
if (!s->has_priority) {
|
||||
s->has_priority = 1;
|
||||
s->priority = from ? from->priority : sc_update[mod_id]->ul[0]->priority;
|
||||
}
|
||||
if (!s->has_first_rb) {
|
||||
s->has_first_rb = 1;
|
||||
s->first_rb = from ? from->first_rb : sc_update[mod_id]->ul[0]->first_rb;
|
||||
}
|
||||
if (!s->has_maxmcs) {
|
||||
s->has_maxmcs = 1;
|
||||
s->maxmcs = from ? from->maxmcs : sc_update[mod_id]->ul[0]->maxmcs;
|
||||
}
|
||||
if (s->n_sorting == 0) {
|
||||
s->n_sorting = from ? from->n_sorting : sc_update[0]->ul[0]->n_sorting;
|
||||
s->sorting = calloc(s->n_sorting, sizeof(Protocol__FlexUlSorting));
|
||||
if (!s->sorting) s->n_sorting = 0;
|
||||
for (int i = 0; i < s->n_sorting; ++i)
|
||||
s->sorting[i] = from ? from->sorting[i] : sc_update[0]->ul[0]->sorting[i];
|
||||
}
|
||||
if (!s->has_accounting) {
|
||||
s->accounting = from ? from->accounting : sc_update[0]->ul[0]->accounting;
|
||||
}
|
||||
if (!s->scheduler_name) {
|
||||
s->scheduler_name = strdup(from ? from->scheduler_name : sc_update[mod_id]->ul[0]->scheduler_name);
|
||||
}
|
||||
}
|
||||
|
||||
Protocol__FlexUlSlice *get_existing_ul_slice(mid_t mod_id, int id)
|
||||
{
|
||||
for (int i = 0; i < sc_update[mod_id]->n_ul; ++i) {
|
||||
if (id == sc_update[mod_id]->ul[i]->id) {
|
||||
return sc_update[mod_id]->ul[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Protocol__FlexUlSlice *create_new_ul_slice(mid_t mod_id, int id)
|
||||
{
|
||||
LOG_I(FLEXRAN_AGENT,
|
||||
"[%d] Creating UL slice with ID %d, taking default values from UL slice 0\n",
|
||||
mod_id, id);
|
||||
Protocol__FlexUlSlice *to = sc_update[mod_id]->ul[sc_update[mod_id]->n_ul];
|
||||
sc_update[mod_id]->n_ul++;
|
||||
AssertFatal(sc_update[mod_id]->n_ul <= MAX_NUM_SLICES,
|
||||
"cannot create more than MAX_NUM_SLICES\n");
|
||||
to->id = id;
|
||||
return to;
|
||||
}
|
||||
|
||||
void prepare_update_slice_config(mid_t mod_id, Protocol__FlexSliceConfig *sup)
|
||||
{
|
||||
int verified = 1;
|
||||
if (!sc_update[mod_id]) {
|
||||
LOG_E(FLEXRAN_AGENT, "Can not update slice policy (no existing slice profile)\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&sc_update_mtx);
|
||||
/* no need for tests in the current state as there are only two protobuf
|
||||
* bools for intra-/interslice sharing. The function applies new values if
|
||||
* applicable */
|
||||
overwrite_slice_config(mod_id, sc_update[mod_id], sup);
|
||||
|
||||
if (sup->n_dl == 0) {
|
||||
LOG_I(FLEXRAN_AGENT, "[%d] no DL slice configuration in flex_slice_config message\n", mod_id);
|
||||
void update_or_remove_dl(mid_t mod_id, Protocol__FlexSlice *s) {
|
||||
if (s->params_case == PROTOCOL__FLEX_SLICE__PARAMS__NOT_SET
|
||||
&& !s->label && !s->scheduler) {
|
||||
LOG_I(FLEXRAN_AGENT, "remove DL slice ID %d\n", s->id);
|
||||
const int rc = flexran_remove_dl_slice(mod_id, s);
|
||||
if (!rc)
|
||||
LOG_W(FLEXRAN_AGENT, "error while removing slice ID %d\n", s->id);
|
||||
} else {
|
||||
/* verify slice parameters */
|
||||
for (int i = 0; i < sup->n_dl; i++) {
|
||||
if (!sup->dl[i]->has_id) {
|
||||
verified = 0;
|
||||
break;
|
||||
}
|
||||
Protocol__FlexDlSlice *dls = get_existing_dl_slice(mod_id, sup->dl[i]->id);
|
||||
/* fill up so that the slice is complete. This way, we don't need to
|
||||
* worry about it later */
|
||||
fill_dl_slice(mod_id, sup->dl[i], dls);
|
||||
verified = verified && flexran_verify_dl_slice(mod_id, sup->dl[i]);
|
||||
if (!verified) break;
|
||||
}
|
||||
|
||||
/* verify group-based parameters (e.g. sum percentage should not exceed
|
||||
* 100%). Can be used to perform admission control */
|
||||
verified = verified && flexran_verify_group_dl_slices(mod_id,
|
||||
sc_update[mod_id]->dl, sc_update[mod_id]->n_dl, sup->dl, sup->n_dl);
|
||||
|
||||
if (verified) {
|
||||
for (int i = 0; i < sup->n_dl; i++) {
|
||||
/* if all verifications were successful, get existing slice for ID or
|
||||
* create new one and overwrite with the update */
|
||||
Protocol__FlexDlSlice *dls = get_existing_dl_slice(mod_id, sup->dl[i]->id);
|
||||
if (!dls) dls = create_new_dl_slice(mod_id, sup->dl[i]->id);
|
||||
overwrite_slice_config_dl(mod_id, dls, sup->dl[i]);
|
||||
}
|
||||
} else {
|
||||
LOG_E(FLEXRAN_AGENT, "[%d] DL slice verification failed, refusing application\n", mod_id);
|
||||
}
|
||||
LOG_I(FLEXRAN_AGENT, "updating DL slice ID %d\n", s->id);
|
||||
const int rc = flexran_create_dl_slice(mod_id, s);
|
||||
if (rc < 0)
|
||||
LOG_W(FLEXRAN_AGENT,
|
||||
"error while update slice ID %d: flexran_create_dl_slice() -> %d\n",
|
||||
s->id, rc);
|
||||
}
|
||||
}
|
||||
|
||||
verified = 1;
|
||||
if (sup->n_ul == 0) {
|
||||
LOG_I(FLEXRAN_AGENT, "[%d] no UL slice configuration in flex_slice_config message\n", mod_id);
|
||||
void update_or_remove_ul(mid_t mod_id, Protocol__FlexSlice *s) {
|
||||
if (s->params_case == PROTOCOL__FLEX_SLICE__PARAMS__NOT_SET
|
||||
&& !s->label && !s->scheduler) {
|
||||
LOG_I(FLEXRAN_AGENT, "remove UL slice ID %d\n", s->id);
|
||||
const int rc = flexran_remove_ul_slice(mod_id, s);
|
||||
if (!rc)
|
||||
LOG_W(FLEXRAN_AGENT, "error while removing slice ID %d\n", s->id);
|
||||
} else {
|
||||
/* verify slice parameters */
|
||||
for (int i = 0; i < sup->n_ul; i++) {
|
||||
if (!sup->ul[i]->has_id) {
|
||||
verified = 0;
|
||||
break;
|
||||
}
|
||||
Protocol__FlexUlSlice *uls = get_existing_ul_slice(mod_id, sup->ul[i]->id);
|
||||
/* fill up so that the slice is complete. This way, we don't need to
|
||||
* worry about it later */
|
||||
fill_ul_slice(mod_id, sup->ul[i], uls);
|
||||
verified = verified && flexran_verify_ul_slice(mod_id, sup->ul[i]);
|
||||
if (!verified) break;
|
||||
}
|
||||
|
||||
/* verify group-based parameters (e.g. sum percentage should not exceed
|
||||
* 100%). Can be used to perform admission control */
|
||||
verified = verified && flexran_verify_group_ul_slices(mod_id,
|
||||
sc_update[mod_id]->ul, sc_update[mod_id]->n_ul, sup->ul, sup->n_ul);
|
||||
|
||||
if (verified) {
|
||||
for (int i = 0; i < sup->n_ul; i++) {
|
||||
/* if all verifications were successful, get existing slice for ID or
|
||||
* create new one and overwrite with the update */
|
||||
Protocol__FlexUlSlice *uls = get_existing_ul_slice(mod_id, sup->ul[i]->id);
|
||||
if (!uls) uls = create_new_ul_slice(mod_id, sup->ul[i]->id);
|
||||
overwrite_slice_config_ul(mod_id, uls, sup->ul[i]);
|
||||
}
|
||||
} else {
|
||||
LOG_E(FLEXRAN_AGENT, "[%d] UL slice verification failed, refusing application\n", mod_id);
|
||||
}
|
||||
LOG_I(FLEXRAN_AGENT, "updating UL slice ID %d\n", s->id);
|
||||
const int rc = flexran_create_ul_slice(mod_id, s);
|
||||
if (rc < 0)
|
||||
LOG_W(FLEXRAN_AGENT,
|
||||
"error while updating slice ID %d: flexran_create_ul_slice() -> %d)\n",
|
||||
s->id, rc);
|
||||
}
|
||||
pthread_mutex_unlock(&sc_update_mtx);
|
||||
|
||||
perform_slice_config_update_count = 1;
|
||||
}
|
||||
|
||||
int apply_new_slice_config(mid_t mod_id, Protocol__FlexSliceConfig *olds, Protocol__FlexSliceConfig *news)
|
||||
{
|
||||
/* not setting the old configuration is intentional, as it will be picked up
|
||||
* later when reading the configuration. There is thus a direct feedback
|
||||
* whether it has been set. */
|
||||
int changes = 0;
|
||||
if (olds->intraslice_share_active != news->intraslice_share_active) {
|
||||
flexran_set_intraslice_sharing_active(mod_id, news->intraslice_share_active);
|
||||
changes++;
|
||||
}
|
||||
if (olds->interslice_share_active != news->interslice_share_active) {
|
||||
flexran_set_interslice_sharing_active(mod_id, news->interslice_share_active);
|
||||
changes++;
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
||||
int apply_new_slice_dl_config(mid_t mod_id, Protocol__FlexDlSlice *oldc, Protocol__FlexDlSlice *newc)
|
||||
{
|
||||
/* not setting the old configuration is intentional, as it will be picked up
|
||||
* later when reading the configuration. There is thus a direct feedback
|
||||
* whether it has been set. */
|
||||
int changes = 0;
|
||||
int slice_idx = flexran_find_dl_slice(mod_id, newc->id);
|
||||
if (slice_idx < 0) {
|
||||
LOG_W(FLEXRAN_AGENT, "[%d] cannot find index for slice ID %d\n", mod_id, newc->id);
|
||||
return 0;
|
||||
}
|
||||
if (oldc->percentage != newc->percentage) {
|
||||
flexran_set_dl_slice_percentage(mod_id, slice_idx, newc->percentage);
|
||||
changes++;
|
||||
}
|
||||
if (oldc->isolation != newc->isolation) {
|
||||
flexran_set_dl_slice_isolation(mod_id, slice_idx, newc->isolation);
|
||||
changes++;
|
||||
}
|
||||
if (oldc->priority != newc->priority) {
|
||||
flexran_set_dl_slice_priority(mod_id, slice_idx, newc->priority);
|
||||
changes++;
|
||||
}
|
||||
if (oldc->position_low != newc->position_low) {
|
||||
flexran_set_dl_slice_position_low(mod_id, slice_idx, newc->position_low);
|
||||
changes++;
|
||||
}
|
||||
if (oldc->position_high != newc->position_high) {
|
||||
flexran_set_dl_slice_position_high(mod_id, slice_idx, newc->position_high);
|
||||
changes++;
|
||||
}
|
||||
if (oldc->maxmcs != newc->maxmcs) {
|
||||
flexran_set_dl_slice_maxmcs(mod_id, slice_idx, newc->maxmcs);
|
||||
changes++;
|
||||
}
|
||||
if (check_dl_sorting_update(oldc, newc)) {
|
||||
flexran_set_dl_slice_sorting(mod_id, slice_idx, newc->sorting, newc->n_sorting);
|
||||
changes++;
|
||||
}
|
||||
if (oldc->accounting != newc->accounting) {
|
||||
flexran_set_dl_slice_accounting_policy(mod_id, slice_idx, newc->accounting);
|
||||
changes++;
|
||||
}
|
||||
if (!oldc->scheduler_name
|
||||
|| strcmp(oldc->scheduler_name, newc->scheduler_name) != 0) {
|
||||
int ret = flexran_set_dl_slice_scheduler(mod_id, slice_idx, newc->scheduler_name);
|
||||
AssertFatal(ret, "could not set DL slice scheduler for slice %d idx %d\n",
|
||||
newc->id, slice_idx);
|
||||
changes++;
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
||||
int apply_new_slice_ul_config(mid_t mod_id, Protocol__FlexUlSlice *oldc, Protocol__FlexUlSlice *newc)
|
||||
{
|
||||
/* not setting the old configuration is intentional, as it will be picked up
|
||||
* later when reading the configuration. There is thus a direct feedback
|
||||
* whether it has been set. */
|
||||
int changes = 0;
|
||||
int slice_idx = flexran_find_ul_slice(mod_id, newc->id);
|
||||
if (slice_idx < 0) {
|
||||
LOG_W(FLEXRAN_AGENT, "[%d] cannot find index for slice ID %d\n", mod_id, newc->id);
|
||||
return 0;
|
||||
}
|
||||
if (oldc->percentage != newc->percentage) {
|
||||
flexran_set_ul_slice_percentage(mod_id, slice_idx, newc->percentage);
|
||||
changes++;
|
||||
}
|
||||
if (oldc->isolation != newc->isolation) {
|
||||
/*flexran_set_ul_slice_isolation(mod_id, slice_idx, newc->isolation);
|
||||
*changes++;*/
|
||||
LOG_W(FLEXRAN_AGENT, "[%d][UL slice %d] setting isolation is not supported\n",
|
||||
mod_id, newc->id);
|
||||
}
|
||||
if (oldc->priority != newc->priority) {
|
||||
/*flexran_set_ul_slice_priority(mod_id, slice_idx, newc->priority);
|
||||
*changes++;*/
|
||||
LOG_W(FLEXRAN_AGENT, "[%d][UL slice %d] setting the priority is not supported\n",
|
||||
mod_id, newc->id);
|
||||
}
|
||||
if (oldc->first_rb != newc->first_rb) {
|
||||
flexran_set_ul_slice_first_rb(mod_id, slice_idx, newc->first_rb);
|
||||
changes++;
|
||||
}
|
||||
/*if (oldc->length_rb != newc->length_rb) {
|
||||
flexran_set_ul_slice_length_rb(mod_id, slice_idx, newc->length_rb);
|
||||
changes++;
|
||||
LOG_W(FLEXRAN_AGENT, "[%d][UL slice %d] setting length_rb is not supported\n",
|
||||
mod_id, newc->id);
|
||||
}*/
|
||||
if (oldc->maxmcs != newc->maxmcs) {
|
||||
flexran_set_ul_slice_maxmcs(mod_id, slice_idx, newc->maxmcs);
|
||||
changes++;
|
||||
}
|
||||
/*if (check_ul_sorting_update(oldc, newc)) {
|
||||
flexran_set_ul_slice_sorting(mod_id, slice_idx, newc->sorting, n);
|
||||
changes++;
|
||||
LOG_W(FLEXRAN_AGENT, "[%d][UL slice %d] setting the sorting is not supported\n",
|
||||
mod_id, newc->id);
|
||||
}*/
|
||||
if (oldc->accounting != newc->accounting) {
|
||||
/*flexran_set_ul_slice_accounting_policy(mod_id, slice_idx, newc->accounting);
|
||||
*changes++;*/
|
||||
LOG_W(FLEXRAN_AGENT, "[%d][UL slice %d] setting the accounting is not supported\n",
|
||||
mod_id, newc->id);
|
||||
}
|
||||
if (!oldc->scheduler_name
|
||||
|| strcmp(oldc->scheduler_name, newc->scheduler_name) != 0) {
|
||||
int ret = flexran_set_ul_slice_scheduler(mod_id, slice_idx, newc->scheduler_name);
|
||||
AssertFatal(ret, "could not set DL slice scheduler for slice %d idx %d\n",
|
||||
newc->id, slice_idx);
|
||||
changes++;
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
||||
void prepare_ue_slice_assoc_update(mid_t mod_id, Protocol__FlexUeConfig *ue_config)
|
||||
{
|
||||
if (n_ue_slice_assoc_updates == MAX_NUM_SLICES) {
|
||||
LOG_E(FLEXRAN_AGENT,
|
||||
"[%d] can not handle flex_ue_config message, buffer is full; try again later\n",
|
||||
mod_id);
|
||||
void apply_update_dl_slice_config(mid_t mod_id, Protocol__FlexSliceDlUlConfig *dl) {
|
||||
if (!dl)
|
||||
return;
|
||||
|
||||
Protocol__FlexSliceAlgorithm dl_algo = flexran_get_dl_slice_algo(mod_id);
|
||||
if (dl->has_algorithm && dl_algo != dl->algorithm) {
|
||||
LOG_I(FLEXRAN_AGENT, "loading new DL slice algorithm %d\n", dl->algorithm);
|
||||
dl_algo = dl->algorithm;
|
||||
flexran_set_dl_slice_algo(mod_id, dl_algo);
|
||||
}
|
||||
|
||||
/* first update existing slices, then create new. Thus, we go through the
|
||||
* list twice. First round, if a slice exists, handle and mark as such. Then,
|
||||
* apply all others in the second round */
|
||||
if (dl->n_slices > 0) {
|
||||
if (dl_algo == PROTOCOL__FLEX_SLICE_ALGORITHM__None) {
|
||||
LOG_E(FLEXRAN_AGENT, "cannot update slices: no algorithm loaded\n");
|
||||
return;
|
||||
}
|
||||
int handled_dl[dl->n_slices];
|
||||
for (int i = 0; i < dl->n_slices; ++i) {
|
||||
if (flexran_find_dl_slice(mod_id, dl->slices[i]->id) < 0) {
|
||||
handled_dl[i] = 0;
|
||||
continue;
|
||||
}
|
||||
update_or_remove_dl(mod_id, dl->slices[i]);
|
||||
handled_dl[i] = 1;
|
||||
}
|
||||
for (int i = 0; i < dl->n_slices; ++i) {
|
||||
if (handled_dl[i])
|
||||
continue;
|
||||
update_or_remove_dl(mod_id, dl->slices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (dl->scheduler) {
|
||||
if (dl_algo != PROTOCOL__FLEX_SLICE_ALGORITHM__None) {
|
||||
LOG_E(FLEXRAN_AGENT, "cannot update scheduling algorithm: slice algorithm loaded\n");
|
||||
return;
|
||||
}
|
||||
LOG_I(FLEXRAN_AGENT, "loading DL new scheduling algorithm '%s'\n", dl->scheduler);
|
||||
const int rc = flexran_set_dl_scheduler(mod_id, dl->scheduler);
|
||||
if (rc < 0) {
|
||||
LOG_E(FLEXRAN_AGENT,
|
||||
"error while updating scheduling algorithm: "
|
||||
"flexran_update_dl_sched_algo() -> %d)\n",
|
||||
rc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void apply_update_ul_slice_config(mid_t mod_id, Protocol__FlexSliceDlUlConfig *ul) {
|
||||
if (!ul)
|
||||
return;
|
||||
|
||||
Protocol__FlexSliceAlgorithm ul_algo = flexran_get_ul_slice_algo(mod_id);
|
||||
if (ul->has_algorithm && ul_algo != ul->algorithm) {
|
||||
LOG_I(FLEXRAN_AGENT, "loading new UL slice algorithm %d\n", ul->algorithm);
|
||||
ul_algo = ul->algorithm;
|
||||
flexran_set_ul_slice_algo(mod_id, ul_algo);
|
||||
}
|
||||
if (ul->n_slices > 0) {
|
||||
if (ul_algo == PROTOCOL__FLEX_SLICE_ALGORITHM__None) {
|
||||
LOG_E(FLEXRAN_AGENT, "cannot update slices: no algorithm loaded\n");
|
||||
return;
|
||||
}
|
||||
int handled_ul[ul->n_slices];
|
||||
for (int i = 0; i < ul->n_slices; ++i) {
|
||||
if (flexran_find_ul_slice(mod_id, ul->slices[i]->id) < 0) {
|
||||
handled_ul[i] = 0;
|
||||
continue;
|
||||
}
|
||||
update_or_remove_ul(mod_id, ul->slices[i]);
|
||||
handled_ul[i] = 1;
|
||||
}
|
||||
for (int i = 0; i < ul->n_slices; ++i) {
|
||||
if (handled_ul[i])
|
||||
continue;
|
||||
update_or_remove_ul(mod_id, ul->slices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (ul->scheduler) {
|
||||
if (ul_algo != PROTOCOL__FLEX_SLICE_ALGORITHM__None) {
|
||||
LOG_E(FLEXRAN_AGENT, "cannot update scheduling algorithm: slice algorithm loaded\n");
|
||||
return;
|
||||
}
|
||||
LOG_I(FLEXRAN_AGENT, "loading new UL scheduling algorithm '%s'\n", ul->scheduler);
|
||||
const int rc = flexran_set_ul_scheduler(mod_id, ul->scheduler);
|
||||
if (rc < 0) {
|
||||
LOG_E(FLEXRAN_AGENT,
|
||||
"error while updating scheduling algorithm: "
|
||||
"flexran_update_dl_sched_algo() -> %d)\n",
|
||||
rc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int apply_ue_slice_assoc_update(mid_t mod_id, Protocol__FlexUeConfig *ue_config)
|
||||
{
|
||||
if (!ue_config->has_rnti) {
|
||||
LOG_E(FLEXRAN_AGENT,
|
||||
"[%d] cannot update UE to slice association, no RNTI in flex_ue_config message\n",
|
||||
mod_id);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
if (ue_config->has_dl_slice_id)
|
||||
LOG_I(FLEXRAN_AGENT, "[%d] associating UE RNTI %#x to DL slice ID %d\n",
|
||||
mod_id, ue_config->rnti, ue_config->dl_slice_id);
|
||||
if (ue_config->has_ul_slice_id)
|
||||
LOG_I(FLEXRAN_AGENT, "[%d] associating UE RNTI %#x to UL slice ID %d\n",
|
||||
mod_id, ue_config->rnti, ue_config->ul_slice_id);
|
||||
ue_slice_assoc_update[n_ue_slice_assoc_updates++] = ue_config;
|
||||
perform_slice_config_update_count = 2;
|
||||
}
|
||||
|
||||
int apply_ue_slice_assoc_update(mid_t mod_id)
|
||||
{
|
||||
int i;
|
||||
int changes = 0;
|
||||
for (i = 0; i < n_ue_slice_assoc_updates; i++) {
|
||||
int ue_id = find_UE_id(mod_id, ue_slice_assoc_update[i]->rnti);
|
||||
if (ue_id < 0 || ue_id > MAX_MOBILES_PER_ENB){
|
||||
LOG_E(FLEXRAN_AGENT,"UE_id %d is wrong!!\n",ue_id);
|
||||
continue;
|
||||
}
|
||||
if (ue_slice_assoc_update[i]->has_dl_slice_id) {
|
||||
int slice_idx = flexran_find_dl_slice(mod_id, ue_slice_assoc_update[i]->dl_slice_id);
|
||||
if (flexran_dl_slice_exists(mod_id, slice_idx)) {
|
||||
flexran_set_ue_dl_slice_idx(mod_id, ue_id, slice_idx);
|
||||
changes++;
|
||||
} else {
|
||||
LOG_W(FLEXRAN_AGENT, "[%d] DL slice %d does not exist, refusing change\n",
|
||||
mod_id, ue_slice_assoc_update[i]->dl_slice_id);
|
||||
}
|
||||
}
|
||||
if (ue_slice_assoc_update[i]->has_ul_slice_id) {
|
||||
int slice_idx = flexran_find_ul_slice(mod_id, ue_slice_assoc_update[i]->ul_slice_id);
|
||||
if (flexran_ul_slice_exists(mod_id, slice_idx)) {
|
||||
flexran_set_ue_ul_slice_idx(mod_id, ue_id, slice_idx);
|
||||
changes++;
|
||||
} else {
|
||||
LOG_W(FLEXRAN_AGENT, "[%d] UL slice %d does not exist, refusing change\n",
|
||||
mod_id, ue_slice_assoc_update[i]->ul_slice_id);
|
||||
}
|
||||
int UE_id = flexran_get_mac_ue_id_rnti(mod_id, ue_config->rnti);
|
||||
if (ue_config->has_dl_slice_id) {
|
||||
if (flexran_get_dl_slice_algo(mod_id) == PROTOCOL__FLEX_SLICE_ALGORITHM__None) {
|
||||
LOG_E(FLEXRAN_AGENT, "no DL slice algorithm loaded\n");
|
||||
} else {
|
||||
LOG_I(FLEXRAN_AGENT, "[%d] associating UE RNTI %04x - %d/UE %d to DL slice ID %d\n",
|
||||
mod_id, ue_config->rnti, ue_config->rnti, UE_id, ue_config->dl_slice_id);
|
||||
flexran_set_ue_dl_slice_id(mod_id, UE_id, ue_config->dl_slice_id);
|
||||
}
|
||||
}
|
||||
n_ue_slice_assoc_updates = 0;
|
||||
return changes;
|
||||
if (ue_config->has_ul_slice_id) {
|
||||
if (flexran_get_ul_slice_algo(mod_id) == PROTOCOL__FLEX_SLICE_ALGORITHM__None) {
|
||||
LOG_E(FLEXRAN_AGENT, "no UL slice algorithm loaded\n");
|
||||
} else {
|
||||
LOG_I(FLEXRAN_AGENT, "[%d] associating UE RNTI %04x - %d/UE %d to UL slice ID %d\n",
|
||||
mod_id, ue_config->rnti, ue_config->rnti, UE_id, ue_config->ul_slice_id);
|
||||
flexran_set_ue_ul_slice_id(mod_id, UE_id, ue_config->ul_slice_id);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -103,43 +103,11 @@ int load_dl_scheduler_function(mid_t mod_id, const char *function_name);
|
||||
|
||||
/*** Functions for handling a slice config ***/
|
||||
|
||||
/* allocate memory for a Protocol__FlexSliceConfig structure with n_dl DL slice
|
||||
* configs and m_ul UL slice configs */
|
||||
Protocol__FlexSliceConfig *flexran_agent_create_slice_config(int n_dl, int m_ul);
|
||||
|
||||
/* read the general slice parameters via RAN into the given
|
||||
* Protocol__FlexSliceConfig struct */
|
||||
void flexran_agent_read_slice_config(mid_t mod_id, Protocol__FlexSliceConfig *s);
|
||||
|
||||
/* read the DL slice config via the RAN into a given Protocol__FlexDlSlice
|
||||
* struct */
|
||||
void flexran_agent_read_slice_dl_config(mid_t mod_id, int slice_idx, Protocol__FlexDlSlice *dl_slice);
|
||||
|
||||
/* read the UL slice config via the RAN into a given Protocol__FlexUlSlice
|
||||
* struct */
|
||||
void flexran_agent_read_slice_ul_config(mid_t mod_id, int slice_idx, Protocol__FlexUlSlice *ul_slice);
|
||||
|
||||
/* reads content of slice over the sc_update structure, so that it can be
|
||||
* applied later by performing a diff between slice_config and sc_update */
|
||||
void prepare_update_slice_config(mid_t mod_id, Protocol__FlexSliceConfig *slice);
|
||||
|
||||
/* apply generic slice parameters (e.g. intra-/interslice sharing activated or
|
||||
* not) if there are changes. Returns the number of changed parameters. */
|
||||
int apply_new_slice_config(mid_t mod_id, Protocol__FlexSliceConfig *olds, Protocol__FlexSliceConfig *news);
|
||||
|
||||
/* apply new configuration of slice in DL if there are changes between the
|
||||
* parameters. Returns the number of changed parameters. */
|
||||
int apply_new_slice_dl_config(mid_t mod_id, Protocol__FlexDlSlice *oldc, Protocol__FlexDlSlice *newc);
|
||||
|
||||
/* apply new configuration of slice in UL if there are changes between the
|
||||
* parameters. Returns the number of changed parameters. */
|
||||
int apply_new_slice_ul_config(mid_t mod_id, Protocol__FlexUlSlice *oldc, Protocol__FlexUlSlice *newc);
|
||||
|
||||
/* inserts a new ue_config into the structure keeping ue to slice association
|
||||
* updates and marks so it can be applied */
|
||||
void prepare_ue_slice_assoc_update(mid_t mod_id, Protocol__FlexUeConfig *ue_config);
|
||||
/* Prepare the application of a slicing config */
|
||||
void apply_update_dl_slice_config(mid_t mod_id, Protocol__FlexSliceDlUlConfig *slice);
|
||||
void apply_update_ul_slice_config(mid_t mod_id, Protocol__FlexSliceDlUlConfig *slice);
|
||||
|
||||
/* apply a new association between a UE and a slice (both DL and UL) */
|
||||
int apply_ue_slice_assoc_update(mid_t mod_id);
|
||||
int apply_ue_slice_assoc_update(mid_t mod_id, Protocol__FlexUeConfig *ue_config);
|
||||
|
||||
#endif /*FLEXRAN_AGENT_MAC_INTERNAL_H_*/
|
||||
|
||||
@@ -28,346 +28,3 @@
|
||||
|
||||
|
||||
#include "flexran_agent_mac_slice_verification.h"
|
||||
|
||||
/* overlap check for UL slices, helper type */
|
||||
struct sregion_s {
|
||||
int start;
|
||||
int length;
|
||||
};
|
||||
|
||||
/* forward declaration of locally-used verification functions */
|
||||
int flexran_dl_slice_verify_pct(int pct);
|
||||
int flexran_dl_slice_verify_priority(int prio);
|
||||
int flexran_dl_slice_verify_position(int pos_low, int pos_high);
|
||||
int flexran_dl_slice_verify_maxmcs(int maxmcs);
|
||||
int flexran_ul_slice_verify_pct(int pct);
|
||||
int flexran_ul_slice_verify_priority(int prio);
|
||||
int flexran_ul_slice_verify_first_rb(int first_rb);
|
||||
int flexran_ul_slice_verify_maxmcs(int maxmcs);
|
||||
int check_ul_slice_overlap(mid_t mod_id, struct sregion_s *sr, int n);
|
||||
|
||||
int flexran_verify_dl_slice(mid_t mod_id, Protocol__FlexDlSlice *dls)
|
||||
{
|
||||
/* check mandatory parameters */
|
||||
if (!dls->has_id) {
|
||||
LOG_E(FLEXRAN_AGENT, "[%d] Incoming DL slice configuration has no ID\n", mod_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* verify parameters individualy */
|
||||
/* label is enum */
|
||||
if (!flexran_dl_slice_verify_pct(dls->percentage)) {
|
||||
LOG_E(FLEXRAN_AGENT, "[%d][DL slice %d] illegal DL slice percentage (%d)\n",
|
||||
mod_id, dls->id, dls->percentage);
|
||||
return 0;
|
||||
}
|
||||
/* isolation is a protobuf bool */
|
||||
if (!flexran_dl_slice_verify_priority(dls->priority)) {
|
||||
LOG_E(FLEXRAN_AGENT, "[%d][DL slice %d] illegal DL slice priority (%d)\n",
|
||||
mod_id, dls->id, dls->priority);
|
||||
return 0;
|
||||
}
|
||||
if (!flexran_dl_slice_verify_position(dls->position_low, dls->position_high)) {
|
||||
LOG_E(FLEXRAN_AGENT,
|
||||
"[%d][DL slice %d] illegal DL slice position low (%d) and/or high (%d)\n",
|
||||
mod_id, dls->id, dls->position_low, dls->position_high);
|
||||
return 0;
|
||||
}
|
||||
if (!flexran_dl_slice_verify_maxmcs(dls->maxmcs)) {
|
||||
LOG_E(FLEXRAN_AGENT, "[%d][DL slice %d] illegal DL slice max mcs %d\n",
|
||||
mod_id, dls->id, dls->maxmcs);
|
||||
return 0;
|
||||
}
|
||||
if (dls->n_sorting == 0) {
|
||||
LOG_E(FLEXRAN_AGENT, "[%d][DL slice %d] no sorting in DL slice\n",
|
||||
mod_id, dls->id);
|
||||
return 0;
|
||||
}
|
||||
if (!dls->sorting) {
|
||||
LOG_E(FLEXRAN_AGENT, "[%d][DL slice %d] no sorting found in DL slice\n",
|
||||
mod_id, dls->id);
|
||||
return 0;
|
||||
}
|
||||
/* sorting is an enum */
|
||||
/* accounting is an enum */
|
||||
if (!dls->scheduler_name) {
|
||||
LOG_E(FLEXRAN_AGENT, "[%d][DL slice %d] no scheduler name found\n",
|
||||
mod_id, dls->id);
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(dls->scheduler_name, "schedule_ue_spec") != 0) {
|
||||
LOG_E(FLEXRAN_AGENT, "[%d][DL slice %d] setting the scheduler to something "
|
||||
"different than schedule_ue_spec is currently not allowed\n",
|
||||
mod_id, dls->id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int flexran_verify_group_dl_slices(mid_t mod_id, Protocol__FlexDlSlice **existing,
|
||||
int n_ex, Protocol__FlexDlSlice **update, int n_up)
|
||||
{
|
||||
int i, j, n;
|
||||
int pct, pct_orig;
|
||||
/* for every update, array points to existing slice, or NULL if update
|
||||
* creates new slice */
|
||||
Protocol__FlexDlSlice *s[n_up];
|
||||
for (i = 0; i < n_up; i++) {
|
||||
s[i] = NULL;
|
||||
for (j = 0; j < n_ex; j++) {
|
||||
if (existing[j]->id == update[i]->id)
|
||||
s[i] = existing[j];
|
||||
}
|
||||
}
|
||||
|
||||
/* check that number of created and number of added slices in total matches
|
||||
* [1,10] */
|
||||
n = n_ex;
|
||||
for (i = 0; i < n_up; i++) {
|
||||
/* new slice */
|
||||
if (!s[i]) n += 1;
|
||||
/* slice will be deleted */
|
||||
else if (s[i]->percentage == 0) n -= 1;
|
||||
/* else "only" an update */
|
||||
}
|
||||
|
||||
if (n < 1 || n > MAX_NUM_SLICES) {
|
||||
LOG_E(FLEXRAN_AGENT, "[%d] Illegal number of resulting DL slices (%d -> %d)\n",
|
||||
mod_id, n_ex, n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check that the sum of all slices percentages (including removed/added
|
||||
* slices) matches [1,100] */
|
||||
pct = 0;
|
||||
for (i = 0; i < n_ex; i++) {
|
||||
pct += existing[i]->percentage;
|
||||
}
|
||||
pct_orig = pct;
|
||||
for (i = 0; i < n_up; i++) {
|
||||
/* if there is an existing slice, subtract its percentage and add the
|
||||
* update's percentage */
|
||||
if (s[i])
|
||||
pct -= s[i]->percentage;
|
||||
pct += update[i]->percentage;
|
||||
}
|
||||
if (pct < 1 || pct > 100) {
|
||||
LOG_E(FLEXRAN_AGENT,
|
||||
"[%d] invalid total RB share for DL slices (%d%% -> %d%%)\n",
|
||||
mod_id, pct_orig, pct);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int flexran_verify_ul_slice(mid_t mod_id, Protocol__FlexUlSlice *uls)
|
||||
{
|
||||
/* check mandatory parameters */
|
||||
if (!uls->has_id) {
|
||||
LOG_E(FLEXRAN_AGENT, "[%d] Incoming UL slice configuration has no ID\n", mod_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* verify parameters individually */
|
||||
/* label is enum */
|
||||
if (!flexran_ul_slice_verify_pct(uls->percentage)) {
|
||||
LOG_E(FLEXRAN_AGENT, "[%d][UL slice %d] illegal UL slice percentage (%d)\n",
|
||||
mod_id, uls->id, uls->percentage);
|
||||
return 0;
|
||||
}
|
||||
/* isolation is a protobuf bool */
|
||||
if (!flexran_ul_slice_verify_priority(uls->priority)) {
|
||||
LOG_E(FLEXRAN_AGENT, "[%d][UL slice %d] illegal UL slice percentage (%d)\n",
|
||||
mod_id, uls->id, uls->priority);
|
||||
return 0;
|
||||
}
|
||||
if (!flexran_ul_slice_verify_first_rb(uls->first_rb)) {
|
||||
LOG_E(FLEXRAN_AGENT, "[%d][UL slice %d] illegal UL slice first RB (%d)\n",
|
||||
mod_id, uls->id, uls->first_rb);
|
||||
return 0;
|
||||
}
|
||||
if (!flexran_ul_slice_verify_maxmcs(uls->maxmcs)) {
|
||||
LOG_E(FLEXRAN_AGENT, "[%d][UL slice %d] illegal UL slice max mcs (%d)\n",
|
||||
mod_id, uls->id, uls->maxmcs);
|
||||
return 0;
|
||||
}
|
||||
/* TODO
|
||||
if (uls->n_sorting == 0) {
|
||||
LOG_E(FLEXRAN_AGENT, "[%d][UL slice %d] no sorting in UL slice\n",
|
||||
mod_id, uls->id);
|
||||
return 0;
|
||||
}
|
||||
if (!uls->sorting) {
|
||||
LOG_E(FLEXRAN_AGENT, "[%d][UL slice %d] no sorting found in UL slice\n",
|
||||
mod_id, uls->id);
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
/* sorting is an enum */
|
||||
/* accounting is an enum */
|
||||
if (!uls->scheduler_name) {
|
||||
LOG_E(FLEXRAN_AGENT, "[%d][UL slice %d] no scheduler name found\n",
|
||||
mod_id, uls->id);
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(uls->scheduler_name, "schedule_ulsch_rnti") != 0) {
|
||||
LOG_E(FLEXRAN_AGENT, "[%d][UL slice %d] setting the scheduler to something "
|
||||
"different than schedule_ulsch_rnti is currently not allowed\n",
|
||||
mod_id, uls->id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int flexran_verify_group_ul_slices(mid_t mod_id, Protocol__FlexUlSlice **existing,
|
||||
int n_ex, Protocol__FlexUlSlice **update, int n_up)
|
||||
{
|
||||
int i, j, n;
|
||||
int pct, pct_orig;
|
||||
/* for every update, array "s" points to existing slice, or NULL if update
|
||||
* creates new slice; array "offs" gives the offset of this slice */
|
||||
Protocol__FlexUlSlice *s[n_up];
|
||||
int offs[n_up];
|
||||
for (i = 0; i < n_up; i++) {
|
||||
s[i] = NULL;
|
||||
offs[i] = 0;
|
||||
for (j = 0; j < n_ex; j++) {
|
||||
if (existing[j]->id == update[i]->id) {
|
||||
s[i] = existing[j];
|
||||
offs[i] = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check that number of created and number of added slices in total matches
|
||||
* [1,10] */
|
||||
n = n_ex;
|
||||
for (i = 0; i < n_up; i++) {
|
||||
/* new slice */
|
||||
if (!s[i]) n += 1;
|
||||
/* slice will be deleted */
|
||||
else if (s[i]->percentage == 0) n -= 1;
|
||||
/* else "only" an update */
|
||||
}
|
||||
|
||||
if (n < 1 || n > MAX_NUM_SLICES) {
|
||||
LOG_E(FLEXRAN_AGENT, "[%d] Illegal number of resulting UL slices (%d -> %d)\n",
|
||||
mod_id, n_ex, n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check that the sum of all slices percentages (including removed/added
|
||||
* slices) matches [1,100] */
|
||||
pct = 0;
|
||||
for (i = 0; i < n_ex; i++) {
|
||||
pct += existing[i]->percentage;
|
||||
}
|
||||
pct_orig = pct;
|
||||
for (i = 0; i < n_up; i++) {
|
||||
/* if there is an existing slice, subtract its percentage and add the
|
||||
* update's percentage */
|
||||
if (s[i])
|
||||
pct -= s[i]->percentage;
|
||||
pct += update[i]->percentage;
|
||||
}
|
||||
if (pct < 1 || pct > 100) {
|
||||
LOG_E(FLEXRAN_AGENT, "[%d] invalid total RB share (%d%% -> %d%%)\n",
|
||||
mod_id, pct_orig, pct);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check that there is no overlap in slices resulting as the combination of
|
||||
* first_rb and percentage */
|
||||
struct sregion_s sregion[n];
|
||||
const int N_RB = flexran_get_N_RB_UL(mod_id, 0); /* assume PCC */
|
||||
int k = n_ex;
|
||||
for (i = 0; i < n_ex; i++) {
|
||||
sregion[i].start = existing[i]->first_rb;
|
||||
sregion[i].length = existing[i]->percentage * N_RB / 100;
|
||||
}
|
||||
for (i = 0; i < n_up; i++) {
|
||||
ptrdiff_t d = s[i] ? offs[i] : k++;
|
||||
AssertFatal(d >= 0 && d < k, "illegal pointer offset (%ld, k=%d)\n", d, k);
|
||||
sregion[d].start = update[i]->first_rb;
|
||||
sregion[d].length = update[i]->percentage * N_RB / 100;
|
||||
}
|
||||
AssertFatal(k == n, "illegal number of slices while calculating overlap\n");
|
||||
if (!check_ul_slice_overlap(mod_id, sregion, k)) {
|
||||
LOG_E(FLEXRAN_AGENT, "[%d] UL slices are overlapping\n", mod_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int flexran_dl_slice_verify_pct(int pct)
|
||||
{
|
||||
return pct >= 0 && pct <= 100;
|
||||
}
|
||||
|
||||
int flexran_dl_slice_verify_priority(int prio)
|
||||
{
|
||||
return prio >= 0;
|
||||
}
|
||||
|
||||
int flexran_dl_slice_verify_position(int pos_low, int pos_high)
|
||||
{
|
||||
return pos_low < pos_high && pos_low >= 0 && pos_high <= N_RBG_MAX;
|
||||
}
|
||||
|
||||
int flexran_dl_slice_verify_maxmcs(int maxmcs)
|
||||
{
|
||||
return maxmcs >= 0 && maxmcs <= 28;
|
||||
}
|
||||
|
||||
int flexran_ul_slice_verify_pct(int pct)
|
||||
{
|
||||
return pct >= 0 && pct <= 100;
|
||||
}
|
||||
|
||||
int flexran_ul_slice_verify_priority(int prio)
|
||||
{
|
||||
return prio >= 0;
|
||||
}
|
||||
|
||||
int flexran_ul_slice_verify_first_rb(int first_rb)
|
||||
{
|
||||
return first_rb >= 0 && first_rb < 100;
|
||||
}
|
||||
|
||||
int flexran_ul_slice_verify_maxmcs(int maxmcs)
|
||||
{
|
||||
return maxmcs >= 0 && maxmcs <= 20;
|
||||
}
|
||||
|
||||
int sregion_compare(const void *_a, const void *_b)
|
||||
{
|
||||
const struct sregion_s *a = (const struct sregion_s *)_a;
|
||||
const struct sregion_s *b = (const struct sregion_s *)_b;
|
||||
const int res = a->start - b->start;
|
||||
if (res < 0) return -1;
|
||||
else if (res == 0) return 0;
|
||||
else return 1;
|
||||
}
|
||||
|
||||
int check_ul_slice_overlap(mid_t mod_id, struct sregion_s *sr, int n)
|
||||
{
|
||||
int i;
|
||||
int overlap, op, u;
|
||||
const int N_RB = flexran_get_N_RB_UL(mod_id, 0); /* assume PCC */
|
||||
qsort(sr, n, sizeof(sr[0]), sregion_compare);
|
||||
for (i = 0; i < n; i++) {
|
||||
u = i == n-1 ? N_RB : sr[i+1].start;
|
||||
AssertFatal(sr[i].start <= u, "unsorted slice list\n");
|
||||
overlap = sr[i].start + sr[i].length - u;
|
||||
if (overlap <= 0) continue;
|
||||
op = overlap * 100 / sr[i].length;
|
||||
LOG_W(FLEXRAN_AGENT, "[%d] slice overlap of %d%% detected\n", mod_id, op);
|
||||
if (op >= 10) /* more than 10% overlap -> refuse */
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -29,9 +29,3 @@
|
||||
#include "flexran_agent_common_internal.h"
|
||||
#include "flexran_agent_mac_internal.h"
|
||||
|
||||
int flexran_verify_dl_slice(mid_t mod_id, Protocol__FlexDlSlice *dls);
|
||||
int flexran_verify_group_dl_slices(mid_t mod_id, Protocol__FlexDlSlice **existing,
|
||||
int n_ex, Protocol__FlexDlSlice **update, int n_up);
|
||||
int flexran_verify_ul_slice(mid_t mod_id, Protocol__FlexUlSlice *uls);
|
||||
int flexran_verify_group_ul_slices(mid_t mod_id, Protocol__FlexUlSlice **existing,
|
||||
int n_ex, Protocol__FlexUlSlice **update, int n_up);
|
||||
|
||||
@@ -125,6 +125,63 @@ void flexran_agent_s1ap_destroy_stats_reply(Protocol__FlexStatsReply *reply) {
|
||||
}
|
||||
}
|
||||
|
||||
void flexran_agent_handle_mme_update(mid_t mod_id,
|
||||
size_t n_mme,
|
||||
Protocol__FlexS1apMme **mme) {
|
||||
if (n_mme == 0 || n_mme > 1) {
|
||||
LOG_E(FLEXRAN_AGENT, "cannot handle %lu MMEs yet\n", n_mme);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mme[0]->s1_ip) {
|
||||
LOG_E(FLEXRAN_AGENT, "no S1 IP present, cannot handle request\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mme[0]->has_state
|
||||
&& mme[0]->state == PROTOCOL__FLEX_MME_STATE__FLMMES_DISCONNECTED) {
|
||||
int rc = flexran_remove_s1ap_mme(mod_id, 1, &mme[0]->s1_ip);
|
||||
if (rc == 0)
|
||||
LOG_I(FLEXRAN_AGENT, "remove MME at IP %s\n", mme[0]->s1_ip);
|
||||
else
|
||||
LOG_W(FLEXRAN_AGENT,
|
||||
"could not remove MME: flexran_remove_s1ap_mme() returned %d\n",
|
||||
rc);
|
||||
} else {
|
||||
int rc = flexran_add_s1ap_mme(mod_id, 1, &mme[0]->s1_ip);
|
||||
if (rc == 0)
|
||||
LOG_I(FLEXRAN_AGENT, "add MME at IP %s\n", mme[0]->s1_ip);
|
||||
else
|
||||
LOG_W(FLEXRAN_AGENT,
|
||||
"could not add MME: flexran_add_s1ap_mme() returned %d\n",
|
||||
rc);
|
||||
}
|
||||
}
|
||||
|
||||
void flexran_agent_handle_plmn_update(mid_t mod_id,
|
||||
int CC_id,
|
||||
size_t n_plmn,
|
||||
Protocol__FlexPlmn **plmn_id) {
|
||||
if (n_plmn < 1 || n_plmn > 6) {
|
||||
LOG_E(FLEXRAN_AGENT, "cannot handle %lu PLMNs\n", n_plmn);
|
||||
return;
|
||||
}
|
||||
|
||||
/* We assume the controller has checked all the parameters within each
|
||||
* plmn_id */
|
||||
int rc = flexran_set_new_plmn_id(mod_id, CC_id, n_plmn, plmn_id);
|
||||
if (rc == 0) {
|
||||
LOG_I(FLEXRAN_AGENT, "set %lu new PLMNs:\n", n_plmn);
|
||||
for (int i = 0; i < (int)n_plmn; ++i)
|
||||
LOG_I(FLEXRAN_AGENT, " MCC %d MNC %d MNC length %d\n",
|
||||
plmn_id[i]->mcc, plmn_id[i]->mnc, plmn_id[0]->mnc_length);
|
||||
} else {
|
||||
LOG_W(FLEXRAN_AGENT,
|
||||
"could not set new PLMN configuration: flexran_set_new_plmn_id() returned %d\n",
|
||||
rc);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@@ -60,6 +60,17 @@ int flexran_agent_s1ap_stats_reply(mid_t mod_id,
|
||||
/* Free allocated S1AP stats message */
|
||||
void flexran_agent_s1ap_destroy_stats_reply(Protocol__FlexStatsReply *reply);
|
||||
|
||||
/* Add or remove MME updates */
|
||||
void flexran_agent_handle_mme_update(mid_t mod_id,
|
||||
size_t n_mme,
|
||||
Protocol__FlexS1apMme **mme);
|
||||
|
||||
/* Set a new PLMN configuration */
|
||||
void flexran_agent_handle_plmn_update(mid_t mod_id,
|
||||
int CC_id,
|
||||
size_t n_plmn,
|
||||
Protocol__FlexPlmn **plmn_id);
|
||||
|
||||
/* Register technology specific interface callbacks */
|
||||
int flexran_agent_register_s1ap_xface(mid_t mod_id);
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
#define CONFIG_STRING_MACRLC_SCHED_MODE "scheduler_mode"
|
||||
#define CONFIG_MACRLC_PUSCH10xSNR "puSch10xSnr"
|
||||
#define CONFIG_MACRLC_PUCCH10xSNR "puCch10xSnr"
|
||||
#define CONFIG_STRING_MACRLC_DEFAULT_SCHED_DL_ALGO "default_sched_dl_algo"
|
||||
|
||||
/*-------------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
/* MacRLC configuration parameters */
|
||||
@@ -84,6 +85,7 @@
|
||||
{CONFIG_STRING_MACRLC_SCHED_MODE, NULL, 0, strptr:NULL, defstrval:"default", TYPE_STRING, 0}, \
|
||||
{CONFIG_MACRLC_PUSCH10xSNR, NULL, 0, iptr:NULL, defintval:200, TYPE_INT, 0}, \
|
||||
{CONFIG_MACRLC_PUCCH10xSNR, NULL, 0, iptr:NULL, defintval:200, TYPE_INT, 0}, \
|
||||
{CONFIG_STRING_MACRLC_DEFAULT_SCHED_DL_ALGO, NULL, 0, strptr:NULL, defstrval:"round_robin_dl", TYPE_STRING, 0}, \
|
||||
}
|
||||
#define MACRLC_CC_IDX 0
|
||||
#define MACRLC_TRANSPORT_N_PREFERENCE_IDX 1
|
||||
@@ -105,6 +107,7 @@
|
||||
#define MACRLC_SCHED_MODE_IDX 17
|
||||
#define MACRLC_PUSCH10xSNR_IDX 18
|
||||
#define MACRLC_PUCCH10xSNR_IDX 19
|
||||
#define MACRLC_DEFAULT_SCHED_DL_ALGO_IDX 20
|
||||
/*---------------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
#endif
|
||||
|
||||
@@ -61,82 +61,30 @@ enum flex_qam {
|
||||
//
|
||||
// Slice config related structures and enums
|
||||
//
|
||||
enum flex_dl_sorting {
|
||||
|
||||
CR_ROUND = 0; // Highest HARQ first
|
||||
CR_SRB12 = 1; // Highest SRB1+2 first
|
||||
CR_HOL = 2; // Highest HOL first
|
||||
CR_LC = 3; // Greatest RLC buffer first
|
||||
CR_CQI = 4; // Highest CQI first
|
||||
CR_LCP = 5; // Highest LC priority first
|
||||
enum flex_slice_algorithm {
|
||||
None = 0;
|
||||
Static = 1;
|
||||
NVS = 2;
|
||||
}
|
||||
|
||||
enum flex_ul_sorting {
|
||||
CRU_ROUND = 0; // Highest HARQ first
|
||||
CRU_BUF = 1; // Highest BSR first
|
||||
CRU_BTS = 2; // More bytes to schedule first
|
||||
CRU_MCS = 3; // Highest MCS first
|
||||
CRU_LCP = 4; // Highest LC priority first
|
||||
CRU_HOL = 5; // Highest HOL first
|
||||
message flex_slice_static {
|
||||
optional uint32 posLow = 1;
|
||||
optional uint32 posHigh = 2;
|
||||
}
|
||||
|
||||
enum flex_dl_accounting_policy {
|
||||
POL_FAIR = 0;
|
||||
POL_GREEDY = 1;
|
||||
POL_NUM = 2;
|
||||
message flex_slice {
|
||||
optional uint32 id = 1;
|
||||
optional string label = 2;
|
||||
optional string scheduler = 3;
|
||||
oneof params {
|
||||
flex_slice_static static = 10;
|
||||
}
|
||||
}
|
||||
|
||||
enum flex_ul_accounting_policy {
|
||||
POLU_FAIR = 0;
|
||||
POLU_GREEDY = 1;
|
||||
POLU_NUM = 2;
|
||||
}
|
||||
|
||||
enum flex_slice_label {
|
||||
xMBB = 0;
|
||||
URLLC = 1;
|
||||
mMTC = 2;
|
||||
xMTC = 3;
|
||||
Other = 4;
|
||||
}
|
||||
|
||||
message flex_dl_slice {
|
||||
optional uint32 id = 1;
|
||||
optional flex_slice_label label = 2;
|
||||
// should be between 0 and 100
|
||||
optional uint32 percentage = 3;
|
||||
// whether this slice should be exempted form interslice sharing
|
||||
optional bool isolation = 4;
|
||||
// increasing value means increasing prio
|
||||
optional uint32 priority = 5;
|
||||
// min and max RB to use (in frequency) in the range [0, N_RBG_MAX]
|
||||
optional uint32 position_low = 6;
|
||||
optional uint32 position_high = 7;
|
||||
// maximum MCS to be allowed in this slice
|
||||
optional uint32 maxmcs = 8;
|
||||
repeated flex_dl_sorting sorting = 9;
|
||||
optional flex_dl_accounting_policy accounting = 10;
|
||||
optional string scheduler_name = 11;
|
||||
}
|
||||
|
||||
message flex_ul_slice {
|
||||
optional uint32 id = 1;
|
||||
optional flex_slice_label label = 2;
|
||||
// should be between 0 and 100
|
||||
optional uint32 percentage = 3;
|
||||
// whether this slice should be exempted form interslice sharing
|
||||
optional bool isolation = 4;
|
||||
// increasing value means increasing prio
|
||||
optional uint32 priority = 5;
|
||||
// RB start to use (in frequency) in the range [0, N_RB_MAX]
|
||||
optional uint32 first_rb = 6;
|
||||
// TODO RB number
|
||||
//optional uint32 length_rb = 7;
|
||||
// maximum MCS to be allowed in this slice
|
||||
optional uint32 maxmcs = 8;
|
||||
repeated flex_ul_sorting sorting = 9;
|
||||
optional flex_ul_accounting_policy accounting = 10;
|
||||
optional string scheduler_name = 11;
|
||||
message flex_slice_dl_ul_config {
|
||||
optional flex_slice_algorithm algorithm = 1;
|
||||
repeated flex_slice slices = 2;
|
||||
optional string scheduler = 3; // if no slicing
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -49,14 +49,8 @@ message flex_cell_config {
|
||||
}
|
||||
|
||||
message flex_slice_config {
|
||||
// whether remaining RBs after first intra-slice allocation will
|
||||
// be allocated to UEs of the same slice
|
||||
optional bool intraslice_share_active = 3;
|
||||
// whether remaining RBs after slice allocation will be allocated
|
||||
// to UEs of another slice. Isolated slices will be ignored.
|
||||
optional bool interslice_share_active = 4;
|
||||
repeated flex_dl_slice dl = 1;
|
||||
repeated flex_ul_slice ul = 2;
|
||||
optional flex_slice_dl_ul_config dl = 6;
|
||||
optional flex_slice_dl_ul_config ul = 7;
|
||||
}
|
||||
|
||||
message flex_ue_config {
|
||||
|
||||
@@ -273,7 +273,6 @@ void *eNB_app_task(void *args_p) {
|
||||
if (EPC_MODE_ENABLED) {
|
||||
LOG_I(ENB_APP, "[eNB %d] Received %s: associated MME %d\n", instance, ITTI_MSG_NAME (msg_p),
|
||||
S1AP_REGISTER_ENB_CNF(msg_p).nb_mme);
|
||||
DevAssert(register_enb_pending > 0);
|
||||
register_enb_pending--;
|
||||
|
||||
/* Check if at least eNB is registered with one MME */
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "assertions.h"
|
||||
@@ -260,6 +261,16 @@ void RCconfig_macrlc(int macrlc_has_f1[MAX_MAC_INST]) {
|
||||
global_scheduler_mode=SCHED_MODE_DEFAULT;
|
||||
printf("sched mode = default %d [%s]\n",global_scheduler_mode,*(MacRLC_ParamList.paramarray[j][MACRLC_SCHED_MODE_IDX].strptr));
|
||||
}
|
||||
|
||||
char *s = *MacRLC_ParamList.paramarray[j][MACRLC_DEFAULT_SCHED_DL_ALGO_IDX].strptr;
|
||||
void *d = dlsym(NULL, s);
|
||||
AssertFatal(d, "%s(): no default scheduler DL algo '%s' found\n", __func__, s);
|
||||
// release default, add new
|
||||
pp_impl_param_t *dl_pp = &RC.mac[j]->pre_processor_dl;
|
||||
dl_pp->dl_algo.unset(&dl_pp->dl_algo.data);
|
||||
dl_pp->dl_algo = *(default_sched_dl_algo_t *) d;
|
||||
dl_pp->dl_algo.data = dl_pp->dl_algo.setup();
|
||||
LOG_I(ENB_APP, "using default scheduler DL algo '%s'\n", dl_pp->dl_algo.name);
|
||||
}// j=0..num_inst
|
||||
} /*else {// MacRLC_ParamList.numelt > 0 // ignore it
|
||||
|
||||
|
||||
@@ -306,6 +306,7 @@ int flexran_agent_destroy_enb_config_reply(Protocol__FlexranMessage *msg) {
|
||||
if (reply->cell_config[i]->mbsfn_subframe_config_sfalloc)
|
||||
free(reply->cell_config[i]->mbsfn_subframe_config_sfalloc);
|
||||
|
||||
/* si_config is shared between MAC and RRC, free here */
|
||||
if (reply->cell_config[i]->si_config) {
|
||||
for(int j = 0; j < reply->cell_config[i]->si_config->n_si_message; j++) {
|
||||
free(reply->cell_config[i]->si_config->si_message[j]);
|
||||
@@ -316,26 +317,7 @@ int flexran_agent_destroy_enb_config_reply(Protocol__FlexranMessage *msg) {
|
||||
}
|
||||
|
||||
if (reply->cell_config[i]->slice_config) {
|
||||
for (int j = 0; j < reply->cell_config[i]->slice_config->n_dl; ++j) {
|
||||
if (reply->cell_config[i]->slice_config->dl[j]->n_sorting > 0)
|
||||
free(reply->cell_config[i]->slice_config->dl[j]->sorting);
|
||||
|
||||
free(reply->cell_config[i]->slice_config->dl[j]->scheduler_name);
|
||||
free(reply->cell_config[i]->slice_config->dl[j]);
|
||||
}
|
||||
|
||||
free(reply->cell_config[i]->slice_config->dl);
|
||||
|
||||
for (int j = 0; j < reply->cell_config[i]->slice_config->n_ul; ++j) {
|
||||
if (reply->cell_config[i]->slice_config->ul[j]->n_sorting > 0)
|
||||
free(reply->cell_config[i]->slice_config->ul[j]->sorting);
|
||||
|
||||
free(reply->cell_config[i]->slice_config->ul[j]->scheduler_name);
|
||||
free(reply->cell_config[i]->slice_config->ul[j]);
|
||||
}
|
||||
|
||||
free(reply->cell_config[i]->slice_config->ul);
|
||||
free(reply->cell_config[i]->slice_config);
|
||||
flexran_agent_destroy_mac_slice_config(reply->cell_config[i]);
|
||||
}
|
||||
|
||||
free(reply->cell_config[i]);
|
||||
@@ -893,31 +875,40 @@ int flexran_agent_handle_enb_config_reply(mid_t mod_id, const void *params, Prot
|
||||
Protocol__FlexranMessage *input = (Protocol__FlexranMessage *)params;
|
||||
Protocol__FlexEnbConfigReply *enb_config = input->enb_config_reply_msg;
|
||||
|
||||
if (enb_config->n_cell_config == 0) {
|
||||
LOG_W(FLEXRAN_AGENT,
|
||||
"received enb_config_reply message does not contain a cell_config\n");
|
||||
*msg = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (enb_config->n_cell_config > 1)
|
||||
LOG_W(FLEXRAN_AGENT, "ignoring slice configs for other cell except cell 0\n");
|
||||
|
||||
if (flexran_agent_get_mac_xface(mod_id) && enb_config->cell_config[0]->slice_config) {
|
||||
prepare_update_slice_config(mod_id, enb_config->cell_config[0]->slice_config);
|
||||
} else if (enb_config->cell_config[0]->has_eutra_band
|
||||
&& enb_config->cell_config[0]->has_dl_freq
|
||||
&& enb_config->cell_config[0]->has_ul_freq
|
||||
&& enb_config->cell_config[0]->has_dl_bandwidth) {
|
||||
initiate_soft_restart(mod_id, enb_config->cell_config[0]);
|
||||
} else if (flexran_agent_get_rrc_xface(mod_id)
|
||||
&& enb_config->cell_config[0]->has_x2_ho_net_control) {
|
||||
LOG_I(FLEXRAN_AGENT,
|
||||
"setting X2 HO NetControl to %d\n",
|
||||
enb_config->cell_config[0]->x2_ho_net_control);
|
||||
const int rc = flexran_set_x2_ho_net_control(mod_id, enb_config->cell_config[0]->x2_ho_net_control);
|
||||
if (rc < 0)
|
||||
LOG_E(FLEXRAN_AGENT, "Error in configuring X2 handover controlled by network");
|
||||
if (enb_config->n_cell_config > 0) {
|
||||
if (flexran_agent_get_mac_xface(mod_id) && enb_config->cell_config[0]->slice_config) {
|
||||
prepare_update_slice_config(mod_id, &enb_config->cell_config[0]->slice_config);
|
||||
}
|
||||
if (enb_config->cell_config[0]->has_eutra_band
|
||||
&& enb_config->cell_config[0]->has_dl_freq
|
||||
&& enb_config->cell_config[0]->has_ul_freq
|
||||
&& enb_config->cell_config[0]->has_dl_bandwidth) {
|
||||
initiate_soft_restart(mod_id, enb_config->cell_config[0]);
|
||||
}
|
||||
if (flexran_agent_get_rrc_xface(mod_id)
|
||||
&& enb_config->cell_config[0]->has_x2_ho_net_control) {
|
||||
LOG_I(FLEXRAN_AGENT,
|
||||
"setting X2 HO NetControl to %d\n",
|
||||
enb_config->cell_config[0]->x2_ho_net_control);
|
||||
const int rc = flexran_set_x2_ho_net_control(mod_id, enb_config->cell_config[0]->x2_ho_net_control);
|
||||
if (rc < 0)
|
||||
LOG_E(FLEXRAN_AGENT, "Error in configuring X2 handover controlled by network");
|
||||
}
|
||||
if (flexran_agent_get_rrc_xface(mod_id) && enb_config->cell_config[0]->n_plmn_id > 0) {
|
||||
flexran_agent_handle_plmn_update(mod_id,
|
||||
0,
|
||||
enb_config->cell_config[0]->n_plmn_id,
|
||||
enb_config->cell_config[0]->plmn_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (flexran_agent_get_s1ap_xface(mod_id) && enb_config->s1ap) {
|
||||
flexran_agent_handle_mme_update(mod_id,
|
||||
enb_config->s1ap->n_mme,
|
||||
enb_config->s1ap->mme);
|
||||
}
|
||||
|
||||
*msg = NULL;
|
||||
@@ -930,7 +921,11 @@ int flexran_agent_handle_ue_config_reply(mid_t mod_id, const void *params, Proto
|
||||
Protocol__FlexUeConfigReply *ue_config_reply = input->ue_config_reply_msg;
|
||||
|
||||
for (i = 0; flexran_agent_get_mac_xface(mod_id) && i < ue_config_reply->n_ue_config; i++)
|
||||
prepare_ue_slice_assoc_update(mod_id, ue_config_reply->ue_config[i]);
|
||||
prepare_ue_slice_assoc_update(mod_id, &ue_config_reply->ue_config[i]);
|
||||
/* prepare_ue_slice_assoc_update takes ownership of the individual
|
||||
* FlexUeConfig messages. Therefore, mark zero messages to not accidentally
|
||||
* free them twice */
|
||||
ue_config_reply->n_ue_config = 0;
|
||||
|
||||
*msg = NULL;
|
||||
return 0;
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "flexran_agent_ran_api.h"
|
||||
#include "s1ap_eNB_ue_context.h"
|
||||
#include "s1ap_eNB_management_procedures.h"
|
||||
#include "openair2/LAYER2/MAC/slicing/slicing.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];
|
||||
@@ -3013,471 +3014,293 @@ uint32_t flexran_get_rrc_enb_ue_s1ap_id(mid_t mod_id, rnti_t rnti)
|
||||
}
|
||||
|
||||
/**************************** SLICING ****************************/
|
||||
int flexran_get_ue_dl_slice_id(mid_t mod_id, mid_t ue_id) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
Protocol__FlexSliceAlgorithm flexran_get_dl_slice_algo(mid_t mod_id) {
|
||||
if (!mac_is_present(mod_id)) return PROTOCOL__FLEX_SLICE_ALGORITHM__None;
|
||||
|
||||
int slice_idx = 0; //RC.mac[mod_id]->UE_info.assoc_dl_slice_idx[ue_id];
|
||||
|
||||
if (slice_idx >= 0 && slice_idx < RC.mac[mod_id]->slice_info.n_dl)
|
||||
return RC.mac[mod_id]->slice_info.dl[slice_idx].id;
|
||||
|
||||
return 0;
|
||||
switch (RC.mac[mod_id]->pre_processor_dl.algorithm) {
|
||||
case STATIC_SLICING:
|
||||
return PROTOCOL__FLEX_SLICE_ALGORITHM__Static;
|
||||
default:
|
||||
return PROTOCOL__FLEX_SLICE_ALGORITHM__None;
|
||||
}
|
||||
}
|
||||
|
||||
void flexran_set_ue_dl_slice_idx(mid_t mod_id, mid_t ue_id, int slice_idx) {
|
||||
int flexran_set_dl_slice_algo(mid_t mod_id, Protocol__FlexSliceAlgorithm algo) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
eNB_MAC_INST *mac = RC.mac[mod_id];
|
||||
const int cc_id = 0;
|
||||
|
||||
pp_impl_param_t dl = mac->pre_processor_dl;
|
||||
switch (algo) {
|
||||
case PROTOCOL__FLEX_SLICE_ALGORITHM__Static:
|
||||
mac->pre_processor_dl = static_dl_init(mod_id, cc_id);
|
||||
break;
|
||||
default:
|
||||
mac->pre_processor_dl.algorithm = 0;
|
||||
mac->pre_processor_dl.dl = dlsch_scheduler_pre_processor;
|
||||
mac->pre_processor_dl.dl_algo.data = mac->pre_processor_dl.dl_algo.setup();
|
||||
mac->pre_processor_dl.slices = NULL;
|
||||
break;
|
||||
}
|
||||
if (dl.slices)
|
||||
dl.destroy(&dl.slices);
|
||||
if (dl.dl_algo.data)
|
||||
dl.dl_algo.unset(&dl.dl_algo.data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
Protocol__FlexSliceAlgorithm flexran_get_ul_slice_algo(mid_t mod_id) {
|
||||
if (!mac_is_present(mod_id)) return PROTOCOL__FLEX_SLICE_ALGORITHM__None;
|
||||
|
||||
switch (RC.mac[mod_id]->pre_processor_ul.algorithm) {
|
||||
case STATIC_SLICING:
|
||||
return PROTOCOL__FLEX_SLICE_ALGORITHM__Static;
|
||||
default:
|
||||
return PROTOCOL__FLEX_SLICE_ALGORITHM__None;
|
||||
}
|
||||
}
|
||||
|
||||
int flexran_set_ul_slice_algo(mid_t mod_id, Protocol__FlexSliceAlgorithm algo) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
eNB_MAC_INST *mac = RC.mac[mod_id];
|
||||
const int cc_id = 0;
|
||||
|
||||
pp_impl_param_t ul = mac->pre_processor_ul;
|
||||
switch (algo) {
|
||||
case PROTOCOL__FLEX_SLICE_ALGORITHM__Static:
|
||||
mac->pre_processor_ul = static_ul_init(mod_id, cc_id);
|
||||
break;
|
||||
default:
|
||||
mac->pre_processor_ul.algorithm = 0;
|
||||
mac->pre_processor_ul.ul = ulsch_scheduler_pre_processor;
|
||||
mac->pre_processor_ul.ul_algo.data = mac->pre_processor_ul.ul_algo.setup();
|
||||
mac->pre_processor_ul.slices = NULL;
|
||||
break;
|
||||
}
|
||||
if (ul.slices)
|
||||
ul.destroy(&ul.slices);
|
||||
if (ul.ul_algo.data)
|
||||
ul.ul_algo.unset(&ul.ul_algo.data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int flexran_get_ue_dl_slice_id(mid_t mod_id, mid_t ue_id) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
slice_info_t *slices = RC.mac[mod_id]->pre_processor_dl.slices;
|
||||
if (!slices) return -1;
|
||||
const int idx = slices->UE_assoc_slice[ue_id];
|
||||
return slices->s[idx]->id;
|
||||
}
|
||||
|
||||
void flexran_set_ue_dl_slice_id(mid_t mod_id, mid_t ue_id, slice_id_t slice_id) {
|
||||
if (!mac_is_present(mod_id)) return;
|
||||
|
||||
if (flexran_get_mac_ue_crnti(mod_id, ue_id) == NOT_A_RNTI) return;
|
||||
|
||||
if (!flexran_dl_slice_exists(mod_id, slice_idx)) return;
|
||||
|
||||
//RC.mac[mod_id]->UE_info.assoc_dl_slice_idx[ue_id] = slice_idx;
|
||||
int idx = flexran_find_dl_slice(mod_id, slice_id);
|
||||
if (idx < 0) return;
|
||||
pp_impl_param_t *dl = &RC.mac[mod_id]->pre_processor_dl;
|
||||
dl->move_UE(dl->slices, ue_id, idx);
|
||||
}
|
||||
|
||||
int flexran_get_ue_ul_slice_id(mid_t mod_id, mid_t ue_id) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
|
||||
int slice_idx = 0; //RC.mac[mod_id]->UE_info.assoc_ul_slice_idx[ue_id];
|
||||
|
||||
if (slice_idx >= 0 && slice_idx < RC.mac[mod_id]->slice_info.n_ul)
|
||||
return RC.mac[mod_id]->slice_info.ul[slice_idx].id;
|
||||
|
||||
return 0;
|
||||
slice_info_t *slices = RC.mac[mod_id]->pre_processor_ul.slices;
|
||||
if (!slices) return -1;
|
||||
const int idx = slices->UE_assoc_slice[ue_id];
|
||||
return slices->s[idx]->id;
|
||||
}
|
||||
|
||||
void flexran_set_ue_ul_slice_idx(mid_t mod_id, mid_t ue_id, int slice_idx) {
|
||||
void flexran_set_ue_ul_slice_id(mid_t mod_id, mid_t ue_id, slice_id_t slice_id) {
|
||||
if (!mac_is_present(mod_id)) return;
|
||||
|
||||
if (flexran_get_mac_ue_crnti(mod_id, ue_id) == NOT_A_RNTI) return;
|
||||
|
||||
if (!flexran_ul_slice_exists(mod_id, slice_idx)) return;
|
||||
|
||||
//RC.mac[mod_id]->UE_info.assoc_ul_slice_idx[ue_id] = slice_idx;
|
||||
int idx = flexran_find_ul_slice(mod_id, slice_id);
|
||||
if (idx < 0) return;
|
||||
pp_impl_param_t *ul = &RC.mac[mod_id]->pre_processor_ul;
|
||||
ul->move_UE(ul->slices, ue_id, idx);
|
||||
}
|
||||
|
||||
int flexran_dl_slice_exists(mid_t mod_id, int slice_idx) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
|
||||
return slice_idx >= 0 && slice_idx < RC.mac[mod_id]->slice_info.n_dl;
|
||||
int flexran_create_dl_slice(mid_t mod_id, const Protocol__FlexSlice *s) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
void *params = NULL;
|
||||
switch (s->params_case) {
|
||||
case PROTOCOL__FLEX_SLICE__PARAMS_STATIC:
|
||||
params = malloc(sizeof(static_slice_param_t));
|
||||
if (!params) return 0;
|
||||
((static_slice_param_t *)params)->posLow = s->static_->poslow;
|
||||
((static_slice_param_t *)params)->posHigh = s->static_->poshigh;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
pp_impl_param_t *dl = &RC.mac[mod_id]->pre_processor_dl;
|
||||
char *l = s->label ? strdup(s->label) : NULL;
|
||||
void *algo = &dl->dl_algo; // default scheduler
|
||||
if (s->scheduler) {
|
||||
algo = dlsym(NULL, s->scheduler);
|
||||
if (!algo) {
|
||||
free(params);
|
||||
LOG_E(FLEXRAN_AGENT, "cannot locate scheduler '%s'\n", s->scheduler);
|
||||
return -15;
|
||||
}
|
||||
}
|
||||
return dl->addmod_slice(dl->slices, s->id, l, algo, params);
|
||||
}
|
||||
|
||||
int flexran_create_dl_slice(mid_t mod_id, slice_id_t slice_id) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
|
||||
int newidx = RC.mac[mod_id]->slice_info.n_dl;
|
||||
|
||||
if (newidx >= MAX_NUM_SLICES) return -1;
|
||||
|
||||
++RC.mac[mod_id]->slice_info.n_dl;
|
||||
flexran_set_dl_slice_id(mod_id, newidx, slice_id);
|
||||
return newidx;
|
||||
int flexran_remove_dl_slice(mid_t mod_id, const Protocol__FlexSlice *s) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
const int idx = flexran_find_dl_slice(mod_id, s->id);
|
||||
if (idx < 0) return 0;
|
||||
pp_impl_param_t *dl = &RC.mac[mod_id]->pre_processor_dl;
|
||||
return dl->remove_slice(dl->slices, idx);
|
||||
}
|
||||
|
||||
int flexran_find_dl_slice(mid_t mod_id, slice_id_t slice_id) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
|
||||
slice_info_t *sli = &RC.mac[mod_id]->slice_info;
|
||||
int n = sli->n_dl;
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (sli->dl[i].id == slice_id) return i;
|
||||
}
|
||||
|
||||
slice_info_t *si = RC.mac[mod_id]->pre_processor_dl.slices;
|
||||
for (int i = 0; i < si->num; ++i)
|
||||
if (si->s[i]->id == slice_id)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int flexran_remove_dl_slice(mid_t mod_id, int slice_idx) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
|
||||
slice_info_t *sli = &RC.mac[mod_id]->slice_info;
|
||||
|
||||
if (sli->n_dl <= 1) return -1;
|
||||
|
||||
if (sli->dl[slice_idx].sched_name) free(sli->dl[slice_idx].sched_name);
|
||||
|
||||
--sli->n_dl;
|
||||
|
||||
/* move last element to the position of the removed one */
|
||||
if (slice_idx != sli->n_dl)
|
||||
memcpy(&sli->dl[slice_idx], &sli->dl[sli->n_dl], sizeof(sli->dl[sli->n_dl]));
|
||||
|
||||
memset(&sli->dl[sli->n_dl], 0, sizeof(sli->dl[sli->n_dl]));
|
||||
/* all UEs that have been in the old slice are put into slice index 0 */
|
||||
//int *assoc_list = RC.mac[mod_id]->UE_info.assoc_dl_slice_idx;
|
||||
|
||||
//for (int i = 0; i < MAX_MOBILES_PER_ENB; ++i) {
|
||||
// if (assoc_list[i] == slice_idx)
|
||||
// assoc_list[i] = 0;
|
||||
//}
|
||||
|
||||
return 1;
|
||||
void flexran_get_dl_slice(mid_t mod_id,
|
||||
int slice_idx,
|
||||
Protocol__FlexSlice *slice,
|
||||
Protocol__FlexSliceAlgorithm algo) {
|
||||
if (!mac_is_present(mod_id)) return;
|
||||
slice_t *s_ = RC.mac[mod_id]->pre_processor_dl.slices->s[slice_idx];
|
||||
slice->has_id = 1;
|
||||
slice->id = s_->id;
|
||||
slice->label = s_->label;
|
||||
slice->scheduler = s_->dl_algo.name;
|
||||
slice->params_case = PROTOCOL__FLEX_SLICE__PARAMS__NOT_SET;
|
||||
switch (algo) {
|
||||
case PROTOCOL__FLEX_SLICE_ALGORITHM__Static:
|
||||
slice->static_ = malloc(sizeof(Protocol__FlexSliceStatic));
|
||||
if (!slice->static_) return;
|
||||
protocol__flex_slice_static__init(slice->static_);
|
||||
slice->static_->has_poslow = 1;
|
||||
slice->static_->poslow = ((static_slice_param_t *)s_->algo_data)->posLow;
|
||||
slice->static_->has_poshigh = 1;
|
||||
slice->static_->poshigh = ((static_slice_param_t *)s_->algo_data)->posHigh;
|
||||
slice->params_case = PROTOCOL__FLEX_SLICE__PARAMS_STATIC;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int flexran_get_num_dl_slices(mid_t mod_id) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
|
||||
return RC.mac[mod_id]->slice_info.n_dl;
|
||||
}
|
||||
|
||||
int flexran_get_intraslice_sharing_active(mid_t mod_id) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
|
||||
return RC.mac[mod_id]->slice_info.intraslice_share_active;
|
||||
}
|
||||
void flexran_set_intraslice_sharing_active(mid_t mod_id, int intraslice_active) {
|
||||
if (!mac_is_present(mod_id)) return;
|
||||
|
||||
RC.mac[mod_id]->slice_info.intraslice_share_active = intraslice_active;
|
||||
}
|
||||
|
||||
int flexran_get_interslice_sharing_active(mid_t mod_id) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
|
||||
return RC.mac[mod_id]->slice_info.interslice_share_active;
|
||||
}
|
||||
void flexran_set_interslice_sharing_active(mid_t mod_id, int interslice_active) {
|
||||
if (!mac_is_present(mod_id)) return;
|
||||
|
||||
RC.mac[mod_id]->slice_info.interslice_share_active = interslice_active;
|
||||
}
|
||||
|
||||
slice_id_t flexran_get_dl_slice_id(mid_t mod_id, int slice_idx) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
|
||||
return RC.mac[mod_id]->slice_info.dl[slice_idx].id;
|
||||
}
|
||||
void flexran_set_dl_slice_id(mid_t mod_id, int slice_idx, slice_id_t slice_id) {
|
||||
if (!mac_is_present(mod_id)) return;
|
||||
|
||||
RC.mac[mod_id]->slice_info.dl[slice_idx].id = slice_id;
|
||||
}
|
||||
|
||||
int flexran_get_dl_slice_percentage(mid_t mod_id, int slice_idx) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
|
||||
return RC.mac[mod_id]->slice_info.dl[slice_idx].pct * 100.0f;
|
||||
}
|
||||
void flexran_set_dl_slice_percentage(mid_t mod_id, int slice_idx, int percentage) {
|
||||
if (!mac_is_present(mod_id)) return;
|
||||
|
||||
RC.mac[mod_id]->slice_info.dl[slice_idx].pct = percentage / 100.0f;
|
||||
}
|
||||
|
||||
int flexran_get_dl_slice_isolation(mid_t mod_id, int slice_idx) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
|
||||
return RC.mac[mod_id]->slice_info.dl[slice_idx].isol;
|
||||
}
|
||||
void flexran_set_dl_slice_isolation(mid_t mod_id, int slice_idx, int is_isolated) {
|
||||
if (!mac_is_present(mod_id)) return;
|
||||
|
||||
RC.mac[mod_id]->slice_info.dl[slice_idx].isol = is_isolated;
|
||||
}
|
||||
|
||||
int flexran_get_dl_slice_priority(mid_t mod_id, int slice_idx) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
|
||||
return RC.mac[mod_id]->slice_info.dl[slice_idx].prio;
|
||||
}
|
||||
void flexran_set_dl_slice_priority(mid_t mod_id, int slice_idx, int priority) {
|
||||
if (!mac_is_present(mod_id)) return;
|
||||
|
||||
RC.mac[mod_id]->slice_info.dl[slice_idx].prio = priority;
|
||||
}
|
||||
|
||||
int flexran_get_dl_slice_position_low(mid_t mod_id, int slice_idx) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
|
||||
return RC.mac[mod_id]->slice_info.dl[slice_idx].pos_low;
|
||||
}
|
||||
void flexran_set_dl_slice_position_low(mid_t mod_id, int slice_idx, int poslow) {
|
||||
if (!mac_is_present(mod_id)) return;
|
||||
|
||||
RC.mac[mod_id]->slice_info.dl[slice_idx].pos_low = poslow;
|
||||
}
|
||||
|
||||
int flexran_get_dl_slice_position_high(mid_t mod_id, int slice_idx) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
|
||||
return RC.mac[mod_id]->slice_info.dl[slice_idx].pos_high;
|
||||
}
|
||||
void flexran_set_dl_slice_position_high(mid_t mod_id, int slice_idx, int poshigh) {
|
||||
if (!mac_is_present(mod_id)) return;
|
||||
|
||||
RC.mac[mod_id]->slice_info.dl[slice_idx].pos_high = poshigh;
|
||||
}
|
||||
|
||||
int flexran_get_dl_slice_maxmcs(mid_t mod_id, int slice_idx) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
|
||||
return RC.mac[mod_id]->slice_info.dl[slice_idx].maxmcs;
|
||||
}
|
||||
void flexran_set_dl_slice_maxmcs(mid_t mod_id, int slice_idx, int maxmcs) {
|
||||
if (!mac_is_present(mod_id)) return;
|
||||
|
||||
RC.mac[mod_id]->slice_info.dl[slice_idx].maxmcs = maxmcs;
|
||||
}
|
||||
|
||||
int flexran_get_dl_slice_sorting(mid_t mod_id, int slice_idx, Protocol__FlexDlSorting **sorting_list) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
|
||||
if (!(*sorting_list)) {
|
||||
*sorting_list = calloc(CR_NUM, sizeof(Protocol__FlexDlSorting));
|
||||
|
||||
if (!(*sorting_list)) return -1;
|
||||
}
|
||||
|
||||
uint32_t policy = RC.mac[mod_id]->slice_info.dl[slice_idx].sorting;
|
||||
|
||||
for (int i = 0; i < CR_NUM; i++) {
|
||||
switch (policy >> 4 * (CR_NUM - 1 - i) & 0xF) {
|
||||
case CR_ROUND:
|
||||
(*sorting_list)[i] = PROTOCOL__FLEX_DL_SORTING__CR_ROUND;
|
||||
break;
|
||||
|
||||
case CR_SRB12:
|
||||
(*sorting_list)[i] = PROTOCOL__FLEX_DL_SORTING__CR_SRB12;
|
||||
break;
|
||||
|
||||
case CR_HOL:
|
||||
(*sorting_list)[i] = PROTOCOL__FLEX_DL_SORTING__CR_HOL;
|
||||
break;
|
||||
|
||||
case CR_LC:
|
||||
(*sorting_list)[i] = PROTOCOL__FLEX_DL_SORTING__CR_LC;
|
||||
break;
|
||||
|
||||
case CR_CQI:
|
||||
(*sorting_list)[i] = PROTOCOL__FLEX_DL_SORTING__CR_CQI;
|
||||
break;
|
||||
|
||||
case CR_LCP:
|
||||
(*sorting_list)[i] = PROTOCOL__FLEX_DL_SORTING__CR_LCP;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* this should not happen, but a "default" */
|
||||
(*sorting_list)[i] = PROTOCOL__FLEX_DL_SORTING__CR_ROUND;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return CR_NUM;
|
||||
}
|
||||
void flexran_set_dl_slice_sorting(mid_t mod_id, int slice_idx, Protocol__FlexDlSorting *sorting_list, int n) {
|
||||
if (!mac_is_present(mod_id)) return;
|
||||
|
||||
uint32_t policy = 0;
|
||||
|
||||
for (int i = 0; i < n && i < CR_NUM; i++) {
|
||||
switch (sorting_list[i]) {
|
||||
case PROTOCOL__FLEX_DL_SORTING__CR_ROUND:
|
||||
policy = policy << 4 | CR_ROUND;
|
||||
break;
|
||||
|
||||
case PROTOCOL__FLEX_DL_SORTING__CR_SRB12:
|
||||
policy = policy << 4 | CR_SRB12;
|
||||
break;
|
||||
|
||||
case PROTOCOL__FLEX_DL_SORTING__CR_HOL:
|
||||
policy = policy << 4 | CR_HOL;
|
||||
break;
|
||||
|
||||
case PROTOCOL__FLEX_DL_SORTING__CR_LC:
|
||||
policy = policy << 4 | CR_LC;
|
||||
break;
|
||||
|
||||
case PROTOCOL__FLEX_DL_SORTING__CR_CQI:
|
||||
policy = policy << 4 | CR_CQI;
|
||||
break;
|
||||
|
||||
case PROTOCOL__FLEX_DL_SORTING__CR_LCP:
|
||||
policy = policy << 4 | CR_LCP;
|
||||
break;
|
||||
|
||||
default: /* suppresses warnings */
|
||||
policy = policy << 4 | CR_ROUND;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* fill up with 0 == CR_ROUND */
|
||||
if (CR_NUM > n) policy = policy << 4 * (CR_NUM - n);
|
||||
|
||||
RC.mac[mod_id]->slice_info.dl[slice_idx].sorting = policy;
|
||||
}
|
||||
|
||||
Protocol__FlexDlAccountingPolicy flexran_get_dl_slice_accounting_policy(mid_t mod_id, int slice_idx) {
|
||||
if (!mac_is_present(mod_id)) return PROTOCOL__FLEX_DL_ACCOUNTING_POLICY__POL_FAIR;
|
||||
|
||||
switch (RC.mac[mod_id]->slice_info.dl[slice_idx].accounting) {
|
||||
case POL_FAIR:
|
||||
return PROTOCOL__FLEX_DL_ACCOUNTING_POLICY__POL_FAIR;
|
||||
|
||||
case POL_GREEDY:
|
||||
return PROTOCOL__FLEX_DL_ACCOUNTING_POLICY__POL_GREEDY;
|
||||
|
||||
default:
|
||||
return PROTOCOL__FLEX_DL_ACCOUNTING_POLICY__POL_FAIR;
|
||||
}
|
||||
}
|
||||
void flexran_set_dl_slice_accounting_policy(mid_t mod_id, int slice_idx, Protocol__FlexDlAccountingPolicy accounting) {
|
||||
if (!mac_is_present(mod_id)) return;
|
||||
|
||||
switch (accounting) {
|
||||
case PROTOCOL__FLEX_DL_ACCOUNTING_POLICY__POL_FAIR:
|
||||
RC.mac[mod_id]->slice_info.dl[slice_idx].accounting = POL_FAIR;
|
||||
return;
|
||||
|
||||
case PROTOCOL__FLEX_DL_ACCOUNTING_POLICY__POL_GREEDY:
|
||||
RC.mac[mod_id]->slice_info.dl[slice_idx].accounting = POL_GREEDY;
|
||||
return;
|
||||
|
||||
default:
|
||||
RC.mac[mod_id]->slice_info.dl[slice_idx].accounting = POL_FAIR;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
char *flexran_get_dl_slice_scheduler(mid_t mod_id, int slice_idx) {
|
||||
if (!mac_is_present(mod_id)) return NULL;
|
||||
|
||||
return RC.mac[mod_id]->slice_info.dl[slice_idx].sched_name;
|
||||
}
|
||||
int flexran_set_dl_slice_scheduler(mid_t mod_id, int slice_idx, char *name) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
|
||||
if (RC.mac[mod_id]->slice_info.dl[slice_idx].sched_name)
|
||||
free(RC.mac[mod_id]->slice_info.dl[slice_idx].sched_name);
|
||||
|
||||
RC.mac[mod_id]->slice_info.dl[slice_idx].sched_name = strdup(name);
|
||||
RC.mac[mod_id]->slice_info.dl[slice_idx].sched_cb = dlsym(NULL, name);
|
||||
return RC.mac[mod_id]->slice_info.dl[slice_idx].sched_cb != NULL;
|
||||
if (!RC.mac[mod_id]->pre_processor_dl.slices) return 0;
|
||||
return RC.mac[mod_id]->pre_processor_dl.slices->num;
|
||||
}
|
||||
|
||||
int flexran_create_ul_slice(mid_t mod_id, slice_id_t slice_id) {
|
||||
int flexran_create_ul_slice(mid_t mod_id, const Protocol__FlexSlice *s) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
void *params = NULL;
|
||||
switch (s->params_case) {
|
||||
case PROTOCOL__FLEX_SLICE__PARAMS_STATIC:
|
||||
params = malloc(sizeof(static_slice_param_t));
|
||||
if (!params) return 0;
|
||||
((static_slice_param_t *)params)->posLow = s->static_->poslow;
|
||||
((static_slice_param_t *)params)->posHigh = s->static_->poshigh;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
pp_impl_param_t *ul = &RC.mac[mod_id]->pre_processor_ul;
|
||||
char *l = s->label ? strdup(s->label) : NULL;
|
||||
void *algo = &ul->ul_algo; // default scheduler
|
||||
if (s->scheduler) {
|
||||
algo = dlsym(NULL, s->scheduler);
|
||||
if (!algo) {
|
||||
free(params);
|
||||
LOG_E(FLEXRAN_AGENT, "cannot locate scheduler '%s'\n", s->scheduler);
|
||||
return -15;
|
||||
}
|
||||
}
|
||||
return ul->addmod_slice(ul->slices, s->id, l, algo, params);
|
||||
}
|
||||
|
||||
int newidx = RC.mac[mod_id]->slice_info.n_ul;
|
||||
|
||||
if (newidx >= MAX_NUM_SLICES) return -1;
|
||||
|
||||
++RC.mac[mod_id]->slice_info.n_ul;
|
||||
flexran_set_ul_slice_id(mod_id, newidx, slice_id);
|
||||
return newidx;
|
||||
int flexran_remove_ul_slice(mid_t mod_id, const Protocol__FlexSlice *s) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
const int idx = flexran_find_ul_slice(mod_id, s->id);
|
||||
if (idx < 0) return 0;
|
||||
pp_impl_param_t *ul = &RC.mac[mod_id]->pre_processor_ul;
|
||||
return ul->remove_slice(ul->slices, idx);
|
||||
}
|
||||
|
||||
int flexran_find_ul_slice(mid_t mod_id, slice_id_t slice_id) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
|
||||
slice_info_t *sli = &RC.mac[mod_id]->slice_info;
|
||||
int n = sli->n_ul;
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (sli->ul[i].id == slice_id) return i;
|
||||
}
|
||||
|
||||
slice_info_t *si = RC.mac[mod_id]->pre_processor_ul.slices;
|
||||
for (int i = 0; i < si->num; ++i)
|
||||
if (si->s[i]->id == slice_id)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int flexran_remove_ul_slice(mid_t mod_id, int slice_idx) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
void flexran_get_ul_slice(mid_t mod_id,
|
||||
int slice_idx,
|
||||
Protocol__FlexSlice *slice,
|
||||
Protocol__FlexSliceAlgorithm algo) {
|
||||
if (!mac_is_present(mod_id)) return;
|
||||
slice_t *s_ = RC.mac[mod_id]->pre_processor_ul.slices->s[slice_idx];
|
||||
slice->has_id = 1;
|
||||
slice->id = s_->id;
|
||||
slice->label = s_->label;
|
||||
slice->scheduler = s_->ul_algo.name;
|
||||
slice->params_case = PROTOCOL__FLEX_SLICE__PARAMS__NOT_SET;
|
||||
switch (algo) {
|
||||
case PROTOCOL__FLEX_SLICE_ALGORITHM__Static:
|
||||
slice->static_ = malloc(sizeof(Protocol__FlexSliceStatic));
|
||||
if (!slice->static_) return;
|
||||
protocol__flex_slice_static__init(slice->static_);
|
||||
slice->static_->has_poslow = 1;
|
||||
slice->static_->poslow = ((static_slice_param_t *)s_->algo_data)->posLow;
|
||||
slice->static_->has_poshigh = 1;
|
||||
slice->static_->poshigh = ((static_slice_param_t *)s_->algo_data)->posHigh;
|
||||
slice->params_case = PROTOCOL__FLEX_SLICE__PARAMS_STATIC;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
slice_info_t *sli = &RC.mac[mod_id]->slice_info;
|
||||
|
||||
if (sli->n_ul <= 1) return -1;
|
||||
|
||||
if (sli->ul[slice_idx].sched_name) free(sli->ul[slice_idx].sched_name);
|
||||
|
||||
--sli->n_ul;
|
||||
|
||||
/* move last element to the position of the removed one */
|
||||
if (slice_idx != sli->n_ul)
|
||||
memcpy(&sli->ul[slice_idx], &sli->ul[sli->n_ul], sizeof(sli->ul[sli->n_ul]));
|
||||
|
||||
memset(&sli->ul[sli->n_ul], 0, sizeof(sli->ul[sli->n_ul]));
|
||||
/* all UEs that have been in the old slice are put into slice index 0 */
|
||||
//int *assoc_list = RC.mac[mod_id]->UE_info.assoc_ul_slice_idx;
|
||||
|
||||
//for (int i = 0; i < MAX_MOBILES_PER_ENB; ++i) {
|
||||
// if (assoc_list[i] == slice_idx)
|
||||
// assoc_list[i] = 0;
|
||||
//}
|
||||
|
||||
return sli->n_ul;
|
||||
}
|
||||
|
||||
int flexran_get_num_ul_slices(mid_t mod_id) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
|
||||
return RC.mac[mod_id]->slice_info.n_ul;
|
||||
}
|
||||
|
||||
int flexran_ul_slice_exists(mid_t mod_id, int slice_idx) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
|
||||
return slice_idx >= 0 && slice_idx < RC.mac[mod_id]->slice_info.n_ul;
|
||||
}
|
||||
|
||||
slice_id_t flexran_get_ul_slice_id(mid_t mod_id, int slice_idx) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
|
||||
return RC.mac[mod_id]->slice_info.ul[slice_idx].id;
|
||||
}
|
||||
void flexran_set_ul_slice_id(mid_t mod_id, int slice_idx, slice_id_t slice_id) {
|
||||
if (!mac_is_present(mod_id)) return;
|
||||
|
||||
RC.mac[mod_id]->slice_info.ul[slice_idx].id = slice_id;
|
||||
}
|
||||
|
||||
int flexran_get_ul_slice_percentage(mid_t mod_id, int slice_idx) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
|
||||
return RC.mac[mod_id]->slice_info.ul[slice_idx].pct * 100.0f;
|
||||
}
|
||||
void flexran_set_ul_slice_percentage(mid_t mod_id, int slice_idx, int percentage) {
|
||||
if (!mac_is_present(mod_id)) return;
|
||||
|
||||
RC.mac[mod_id]->slice_info.ul[slice_idx].pct = percentage / 100.0f;
|
||||
}
|
||||
|
||||
int flexran_get_ul_slice_first_rb(mid_t mod_id, int slice_idx) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
|
||||
return RC.mac[mod_id]->slice_info.ul[slice_idx].first_rb;
|
||||
}
|
||||
|
||||
void flexran_set_ul_slice_first_rb(mid_t mod_id, int slice_idx, int first_rb) {
|
||||
if (!mac_is_present(mod_id)) return;
|
||||
|
||||
RC.mac[mod_id]->slice_info.ul[slice_idx].first_rb = first_rb;
|
||||
}
|
||||
|
||||
int flexran_get_ul_slice_maxmcs(mid_t mod_id, int slice_idx) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
|
||||
return RC.mac[mod_id]->slice_info.ul[slice_idx].maxmcs;
|
||||
}
|
||||
void flexran_set_ul_slice_maxmcs(mid_t mod_id, int slice_idx, int maxmcs) {
|
||||
if (!mac_is_present(mod_id)) return;
|
||||
|
||||
RC.mac[mod_id]->slice_info.ul[slice_idx].maxmcs = maxmcs;
|
||||
}
|
||||
|
||||
char *flexran_get_ul_slice_scheduler(mid_t mod_id, int slice_idx) {
|
||||
if (!mac_is_present(mod_id)) return NULL;
|
||||
|
||||
return RC.mac[mod_id]->slice_info.ul[slice_idx].sched_name;
|
||||
}
|
||||
int flexran_set_ul_slice_scheduler(mid_t mod_id, int slice_idx, char *name) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
if (!RC.mac[mod_id]->pre_processor_ul.slices) return 0;
|
||||
return RC.mac[mod_id]->pre_processor_ul.slices->num;
|
||||
}
|
||||
|
||||
if (RC.mac[mod_id]->slice_info.ul[slice_idx].sched_name)
|
||||
free(RC.mac[mod_id]->slice_info.ul[slice_idx].sched_name);
|
||||
char *flexran_get_dl_scheduler_name(mid_t mod_id) {
|
||||
if (!mac_is_present(mod_id)) return NULL;
|
||||
return RC.mac[mod_id]->pre_processor_dl.dl_algo.name;
|
||||
}
|
||||
|
||||
RC.mac[mod_id]->slice_info.ul[slice_idx].sched_name = strdup(name);
|
||||
RC.mac[mod_id]->slice_info.ul[slice_idx].sched_cb = dlsym(NULL, name);
|
||||
return RC.mac[mod_id]->slice_info.ul[slice_idx].sched_cb != NULL;
|
||||
int flexran_set_dl_scheduler(mid_t mod_id, char *sched) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
void *d = dlsym(NULL, sched);
|
||||
if (!d) return -2;
|
||||
pp_impl_param_t *dl_pp = &RC.mac[mod_id]->pre_processor_dl;
|
||||
dl_pp->dl_algo.unset(&dl_pp->dl_algo.data);
|
||||
dl_pp->dl_algo = *(default_sched_dl_algo_t *) d;
|
||||
dl_pp->dl_algo.data = dl_pp->dl_algo.setup();
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *flexran_get_ul_scheduler_name(mid_t mod_id) {
|
||||
if (!mac_is_present(mod_id)) return NULL;
|
||||
return RC.mac[mod_id]->pre_processor_ul.ul_algo.name;
|
||||
}
|
||||
|
||||
int flexran_set_ul_scheduler(mid_t mod_id, char *sched) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
void *d = dlsym(NULL, sched);
|
||||
if (!d) return -2;
|
||||
pp_impl_param_t *ul_pp = &RC.mac[mod_id]->pre_processor_ul;
|
||||
ul_pp->ul_algo.unset(&ul_pp->ul_algo.data);
|
||||
ul_pp->ul_algo = *(default_sched_ul_algo_t *) d;
|
||||
ul_pp->ul_algo.data = ul_pp->ul_algo.setup();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/************************** S1AP **************************/
|
||||
@@ -3634,6 +3457,168 @@ int flexran_get_s1ap_mme_conf(mid_t mod_id, mid_t mme_index, Protocol__FlexS1apM
|
||||
return 0;
|
||||
}
|
||||
|
||||
int flexran_add_s1ap_mme(mid_t mod_id, size_t n_mme, char **mme_ipv4) {
|
||||
s1ap_eNB_instance_t *s1ap = s1ap_eNB_get_instance(mod_id);
|
||||
if (!s1ap) return -1;
|
||||
if (!rrc_is_present(mod_id)) return -2;
|
||||
|
||||
/* Reconstruct S1AP_REGISTER_ENB_REQ */
|
||||
MessageDef *m = itti_alloc_new_message(TASK_FLEXRAN_AGENT, S1AP_REGISTER_ENB_REQ);
|
||||
RCconfig_S1(m, mod_id);
|
||||
|
||||
const int CC_id = 0;
|
||||
eNB_RRC_INST *rrc = RC.rrc[CC_id];
|
||||
RrcConfigurationReq *conf = &rrc->configuration;
|
||||
S1AP_REGISTER_ENB_REQ(m).num_plmn = conf->num_plmn;
|
||||
for (int i = 0; i < conf->num_plmn; ++i) {
|
||||
S1AP_REGISTER_ENB_REQ(m).mcc[i] = conf->mcc[i];
|
||||
S1AP_REGISTER_ENB_REQ(m).mnc[i] = conf->mnc[i];
|
||||
S1AP_REGISTER_ENB_REQ(m).mnc_digit_length[i] = conf->mnc_digit_length[i];
|
||||
}
|
||||
|
||||
/* reconstruct MME list, it might have been updated since initial
|
||||
* configuration */
|
||||
S1AP_REGISTER_ENB_REQ(m).nb_mme = 0;
|
||||
struct s1ap_eNB_mme_data_s *mme = NULL;
|
||||
RB_FOREACH(mme, s1ap_mme_map, &s1ap->s1ap_mme_head) {
|
||||
const int n = S1AP_REGISTER_ENB_REQ(m).nb_mme;
|
||||
S1AP_REGISTER_ENB_REQ(m).mme_ip_address[n].ipv4 = mme->mme_s1_ip.ipv4;
|
||||
strcpy(S1AP_REGISTER_ENB_REQ(m).mme_ip_address[n].ipv4_address, mme->mme_s1_ip.ipv4_address);
|
||||
S1AP_REGISTER_ENB_REQ(m).mme_ip_address[n].ipv6 = mme->mme_s1_ip.ipv6;
|
||||
strcpy(S1AP_REGISTER_ENB_REQ(m).mme_ip_address[n].ipv6_address, mme->mme_s1_ip.ipv6_address);
|
||||
S1AP_REGISTER_ENB_REQ(m).broadcast_plmn_num[n] = mme->broadcast_plmn_num;
|
||||
for (int i = 0; i < mme->broadcast_plmn_num; ++i)
|
||||
S1AP_REGISTER_ENB_REQ(m).broadcast_plmn_index[n][i] = mme->broadcast_plmn_index[i];
|
||||
S1AP_REGISTER_ENB_REQ(m).nb_mme += 1;
|
||||
}
|
||||
|
||||
if (S1AP_REGISTER_ENB_REQ(m).nb_mme + n_mme > S1AP_MAX_NB_MME_IP_ADDRESS)
|
||||
return -1;
|
||||
|
||||
for (int i = 0; i < n_mme; ++i) {
|
||||
const int n = S1AP_REGISTER_ENB_REQ(m).nb_mme;
|
||||
strcpy(S1AP_REGISTER_ENB_REQ(m).mme_ip_address[n].ipv4_address, mme_ipv4[0]);
|
||||
S1AP_REGISTER_ENB_REQ(m).mme_ip_address[n].ipv4 = 1;
|
||||
S1AP_REGISTER_ENB_REQ(m).mme_ip_address[n].ipv6 = 0;
|
||||
S1AP_REGISTER_ENB_REQ(m).broadcast_plmn_num[n] = S1AP_REGISTER_ENB_REQ(m).num_plmn;
|
||||
for (int i = 0; i < S1AP_REGISTER_ENB_REQ(m).num_plmn; ++i)
|
||||
S1AP_REGISTER_ENB_REQ(m).broadcast_plmn_index[n][i] = i;
|
||||
S1AP_REGISTER_ENB_REQ(m).nb_mme += 1;
|
||||
}
|
||||
|
||||
itti_send_msg_to_task (TASK_S1AP, ENB_MODULE_ID_TO_INSTANCE(mod_id), m);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int flexran_remove_s1ap_mme(mid_t mod_id, size_t n_mme, char **mme_ipv4) {
|
||||
s1ap_eNB_instance_t *s1ap = s1ap_eNB_get_instance(mod_id);
|
||||
if (!s1ap) return -1;
|
||||
struct s1ap_eNB_mme_data_s *mme = NULL;
|
||||
RB_FOREACH(mme, s1ap_mme_map, &s1ap->s1ap_mme_head) {
|
||||
if (mme->mme_s1_ip.ipv4
|
||||
&& strncmp(mme->mme_s1_ip.ipv4_address, mme_ipv4[0], 16) == 0)
|
||||
break;
|
||||
}
|
||||
if (!mme)
|
||||
return -2;
|
||||
|
||||
MessageDef *m = itti_alloc_new_message(TASK_FLEXRAN_AGENT, SCTP_CLOSE_ASSOCIATION);
|
||||
SCTP_CLOSE_ASSOCIATION(m).assoc_id = mme->assoc_id;
|
||||
itti_send_msg_to_task (TASK_SCTP, ENB_MODULE_ID_TO_INSTANCE(mod_id), m);
|
||||
|
||||
switch (mme->state) {
|
||||
case S1AP_ENB_STATE_WAITING:
|
||||
s1ap->s1ap_mme_nb -= 1;
|
||||
if (s1ap->s1ap_mme_pending_nb > 0)
|
||||
s1ap->s1ap_mme_pending_nb -= 1;
|
||||
break;
|
||||
case S1AP_ENB_STATE_CONNECTED:
|
||||
case S1AP_ENB_OVERLOAD: /* I am not sure the decrements are right here */
|
||||
s1ap->s1ap_mme_nb -= 1;
|
||||
s1ap->s1ap_mme_associated_nb -= 1;
|
||||
break;
|
||||
case S1AP_ENB_STATE_DISCONNECTED:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
RB_REMOVE(s1ap_mme_map, &s1ap->s1ap_mme_head, mme);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int flexran_set_new_plmn_id(mid_t mod_id, int CC_id, size_t n_plmn, Protocol__FlexPlmn **plmn_id) {
|
||||
if (!rrc_is_present(mod_id))
|
||||
return -1;
|
||||
s1ap_eNB_instance_t *s1ap = s1ap_eNB_get_instance(mod_id);
|
||||
if (!s1ap)
|
||||
return -2;
|
||||
|
||||
eNB_RRC_INST *rrc = RC.rrc[CC_id];
|
||||
RrcConfigurationReq *conf = &rrc->configuration;
|
||||
|
||||
uint8_t num_plmn_old = conf->num_plmn;
|
||||
uint16_t mcc[PLMN_LIST_MAX_SIZE];
|
||||
uint16_t mnc[PLMN_LIST_MAX_SIZE];
|
||||
uint8_t mnc_digit_length[PLMN_LIST_MAX_SIZE];
|
||||
for (int i = 0; i < num_plmn_old; ++i) {
|
||||
mcc[i] = conf->mcc[i];
|
||||
mnc[i] = conf->mnc[i];
|
||||
mnc_digit_length[i] = conf->mnc_digit_length[i];
|
||||
}
|
||||
|
||||
conf->num_plmn = (uint8_t) n_plmn;
|
||||
for (int i = 0; i < conf->num_plmn; ++i) {
|
||||
conf->mcc[i] = plmn_id[i]->mcc;
|
||||
conf->mnc[i] = plmn_id[i]->mnc;
|
||||
conf->mnc_digit_length[i] = plmn_id[i]->mnc_length;
|
||||
}
|
||||
|
||||
rrc_eNB_carrier_data_t *carrier = &rrc->carrier[CC_id];
|
||||
extern uint8_t do_SIB1(rrc_eNB_carrier_data_t *carrier,
|
||||
int Mod_id,
|
||||
int CC_id,
|
||||
BOOLEAN_t brOption,
|
||||
RrcConfigurationReq *configuration);
|
||||
carrier->sizeof_SIB1 = do_SIB1(carrier, mod_id, CC_id, FALSE, conf);
|
||||
if (carrier->sizeof_SIB1 < 0)
|
||||
return -1337; /* SIB1 encoding failed, hell will probably break loose */
|
||||
|
||||
s1ap->num_plmn = (uint8_t) n_plmn;
|
||||
for (int i = 0; i < conf->num_plmn; ++i) {
|
||||
s1ap->mcc[i] = plmn_id[i]->mcc;
|
||||
s1ap->mnc[i] = plmn_id[i]->mnc;
|
||||
s1ap->mnc_digit_length[i] = plmn_id[i]->mnc_length;
|
||||
}
|
||||
|
||||
int bpn_failed = 0;
|
||||
struct s1ap_eNB_mme_data_s *mme = NULL;
|
||||
RB_FOREACH(mme, s1ap_mme_map, &s1ap->s1ap_mme_head) {
|
||||
for (int i = 0; i < mme->broadcast_plmn_num; ++i) {
|
||||
/* search the new index and update. If we don't find, we count this using
|
||||
* bpn_failed to now how many broadcast_plmns could not be updated */
|
||||
int idx = mme->broadcast_plmn_index[i];
|
||||
int omcc = mcc[idx];
|
||||
int omnc = mnc[idx];
|
||||
int omncl = mnc_digit_length[idx];
|
||||
int j = 0;
|
||||
for (j = 0; j < s1ap->num_plmn; ++j) {
|
||||
if (s1ap->mcc[j] == omcc
|
||||
&& s1ap->mnc[j] == omnc
|
||||
&& s1ap->mnc_digit_length[j] == omncl) {
|
||||
mme->broadcast_plmn_index[i] = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j == s1ap->num_plmn) /* could not find the old PLMN in the new ones */
|
||||
bpn_failed++;
|
||||
}
|
||||
}
|
||||
if (bpn_failed > 0)
|
||||
return -10000 - bpn_failed;
|
||||
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);
|
||||
@@ -3644,7 +3629,7 @@ int flexran_get_s1ap_ue(mid_t mod_id, rnti_t rnti, Protocol__FlexS1apUe * ue_con
|
||||
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) return 0; // UE does not exist: it might be connected but CN did not answer
|
||||
|
||||
if (ue->mme_ref->mme_s1_ip.ipv4)
|
||||
ue_conf->mme_s1_ip = (char*) &ue->mme_ref->mme_s1_ip.ipv4_address[0];
|
||||
|
||||
@@ -656,156 +656,66 @@ int flexran_agent_rrc_gtp_get_teid_sgw(mid_t mod_id, rnti_t rnti, int index);
|
||||
uint32_t flexran_get_rrc_enb_ue_s1ap_id(mid_t mod_id, rnti_t rnti);
|
||||
|
||||
/************************** Slice configuration **************************/
|
||||
/* Get the currently active DL slicing algorithm */
|
||||
Protocol__FlexSliceAlgorithm flexran_get_dl_slice_algo(mid_t mod_id);
|
||||
/* Set the active DL slicing algorithm */
|
||||
int flexran_set_dl_slice_algo(mid_t mod_id, Protocol__FlexSliceAlgorithm algo);
|
||||
|
||||
/* Get the currently active UL slicing algorithm */
|
||||
Protocol__FlexSliceAlgorithm flexran_get_ul_slice_algo(mid_t mod_id);
|
||||
/* Set the active UL slicing algorithm */
|
||||
int flexran_set_ul_slice_algo(mid_t mod_id, Protocol__FlexSliceAlgorithm algo);
|
||||
|
||||
/* Get the DL slice ID for a UE */
|
||||
int flexran_get_ue_dl_slice_id(mid_t mod_id, mid_t ue_id);
|
||||
|
||||
/* Set the DL slice index(!) for a UE */
|
||||
void flexran_set_ue_dl_slice_idx(mid_t mod_id, mid_t ue_id, int slice_idx);
|
||||
/* Set the DL slice for a UE */
|
||||
void flexran_set_ue_dl_slice_id(mid_t mod_id, mid_t ue_id, slice_id_t slice_id);
|
||||
|
||||
/* Get the UL slice ID for a UE */
|
||||
int flexran_get_ue_ul_slice_id(mid_t mod_id, mid_t ue_id);
|
||||
/* Set the UL slice for a UE */
|
||||
void flexran_set_ue_ul_slice_id(mid_t mod_id, mid_t ue_id, slice_id_t slice_id);
|
||||
|
||||
/* Set the UL slice index(!) for a UE */
|
||||
void flexran_set_ue_ul_slice_idx(mid_t mod_id, mid_t ue_id, int slice_idx);
|
||||
|
||||
/* Whether intraslice sharing is active, return boolean */
|
||||
int flexran_get_intraslice_sharing_active(mid_t mod_id);
|
||||
/* Set whether intraslice sharing is active */
|
||||
void flexran_set_intraslice_sharing_active(mid_t mod_id, int intraslice_active);
|
||||
|
||||
/* Whether intraslice sharing is active, return boolean */
|
||||
int flexran_get_interslice_sharing_active(mid_t mod_id);
|
||||
/* Set whether intraslice sharing is active */
|
||||
void flexran_set_interslice_sharing_active(mid_t mod_id, int interslice_active);
|
||||
/* Create slice in DL, returns the new slice index */
|
||||
int flexran_create_dl_slice(mid_t mod_id, const Protocol__FlexSlice *s);
|
||||
/* Remove slice in DL, returns new number of slices or -1 on error */
|
||||
int flexran_remove_dl_slice(mid_t mod_id, const Protocol__FlexSlice *s);
|
||||
|
||||
/* Finds slice in DL with given slice_id and returns slice index */
|
||||
int flexran_find_dl_slice(mid_t mod_id, slice_id_t slice_id);
|
||||
/* Return the parameters of slice at index slice_idx */
|
||||
void flexran_get_dl_slice(mid_t mod_id,
|
||||
int slice_idx,
|
||||
Protocol__FlexSlice *slice,
|
||||
Protocol__FlexSliceAlgorithm algo);
|
||||
/* Get the number of slices in DL */
|
||||
int flexran_get_num_dl_slices(mid_t mod_id);
|
||||
|
||||
/* Query slice existence in DL. Return is boolean value */
|
||||
int flexran_dl_slice_exists(mid_t mod_id, int slice_idx);
|
||||
/* Create slice in UL, returns the new slice index */
|
||||
int flexran_create_ul_slice(mid_t mod_id, const Protocol__FlexSlice *s);
|
||||
/* Remove slice in UL */
|
||||
int flexran_remove_ul_slice(mid_t mod_id, const Protocol__FlexSlice *s);
|
||||
|
||||
/* Create slice in DL, returns the new slice index */
|
||||
int flexran_create_dl_slice(mid_t mod_id, slice_id_t slice_id);
|
||||
/* Finds slice in DL with given slice_id and returns slice index */
|
||||
int flexran_find_dl_slice(mid_t mod_id, slice_id_t slice_id);
|
||||
/* Remove slice in DL, returns new number of slices or -1 on error */
|
||||
int flexran_remove_dl_slice(mid_t mod_id, int slice_idx);
|
||||
|
||||
/* Get the ID of a slice in DL */
|
||||
slice_id_t flexran_get_dl_slice_id(mid_t mod_id, int slice_idx);
|
||||
/* Set the ID of a slice in DL */
|
||||
void flexran_set_dl_slice_id(mid_t mod_id, int slice_idx, slice_id_t slice_id);
|
||||
|
||||
/* Get the RB share a slice in DL, value 0-100 */
|
||||
int flexran_get_dl_slice_percentage(mid_t mod_id, int slice_idx);
|
||||
/* Set the RB share a slice in DL, value 0-100 */
|
||||
void flexran_set_dl_slice_percentage(mid_t mod_id, int slice_idx, int percentage);
|
||||
|
||||
/* Whether a slice in DL is isolated */
|
||||
int flexran_get_dl_slice_isolation(mid_t mod_id, int slice_idx);
|
||||
/* Set whether a slice in DL is isolated */
|
||||
void flexran_set_dl_slice_isolation(mid_t mod_id, int slice_idx, int is_isolated);
|
||||
|
||||
/* Get the priority of a slice in DL */
|
||||
int flexran_get_dl_slice_priority(mid_t mod_id, int slice_idx);
|
||||
/* Get the priority of a slice in DL */
|
||||
void flexran_set_dl_slice_priority(mid_t mod_id, int slice_idx, int priority);
|
||||
|
||||
/* Get the lower end of the frequency range for the slice positioning in DL */
|
||||
int flexran_get_dl_slice_position_low(mid_t mod_id, int slice_idx);
|
||||
/* Set the lower end of the frequency range for the slice positioning in DL */
|
||||
void flexran_set_dl_slice_position_low(mid_t mod_id, int slice_idx, int poslow);
|
||||
|
||||
/* Get the higher end of the frequency range for the slice positioning in DL */
|
||||
int flexran_get_dl_slice_position_high(mid_t mod_id, int slice_idx);
|
||||
/* Set the higher end of the frequency range for the slice positioning in DL */
|
||||
void flexran_set_dl_slice_position_high(mid_t mod_id, int slice_idx, int poshigh);
|
||||
|
||||
/* Get the maximum MCS for slice in DL */
|
||||
int flexran_get_dl_slice_maxmcs(mid_t mod_id, int slice_idx);
|
||||
/* Set the maximum MCS for slice in DL */
|
||||
void flexran_set_dl_slice_maxmcs(mid_t mod_id, int slice_idx, int maxmcs);
|
||||
|
||||
/* Get the sorting order of a slice in DL, return value is number of elements
|
||||
* in sorting_list */
|
||||
int flexran_get_dl_slice_sorting(mid_t mod_id, int slice_idx, Protocol__FlexDlSorting **sorting_list);
|
||||
/* Set the sorting order of a slice in DL */
|
||||
void flexran_set_dl_slice_sorting(mid_t mod_id, int slice_idx, Protocol__FlexDlSorting *sorting_list, int n);
|
||||
|
||||
/* Get the accounting policy for a slice in DL */
|
||||
Protocol__FlexDlAccountingPolicy flexran_get_dl_slice_accounting_policy(mid_t mod_id, int slice_idx);
|
||||
/* Set the accounting policy for a slice in DL */
|
||||
void flexran_set_dl_slice_accounting_policy(mid_t mod_id, int slice_idx, Protocol__FlexDlAccountingPolicy accounting);
|
||||
|
||||
/* Get the scheduler name for a slice in DL */
|
||||
char *flexran_get_dl_slice_scheduler(mid_t mod_id, int slice_idx);
|
||||
/* Set the scheduler name for a slice in DL */
|
||||
int flexran_set_dl_slice_scheduler(mid_t mod_id, int slice_idx, char *name);
|
||||
|
||||
int flexran_find_ul_slice(mid_t mod_id, slice_id_t slice_id);
|
||||
/* Return the parameters of slice at index slice_idx */
|
||||
void flexran_get_ul_slice(mid_t mod_id,
|
||||
int slice_idx,
|
||||
Protocol__FlexSlice *slice,
|
||||
Protocol__FlexSliceAlgorithm algo);
|
||||
/* Get the number of slices in UL */
|
||||
int flexran_get_num_ul_slices(mid_t mod_id);
|
||||
|
||||
/* Query slice existence in UL. Return is boolean value */
|
||||
int flexran_ul_slice_exists(mid_t mod_id, int slice_idx);
|
||||
/* Get the name of/Set the DL scheduling algorithm. If slicing is active, this
|
||||
* corresponds to the default algorithm for slices, otherwise the currently
|
||||
* used one. */
|
||||
char *flexran_get_dl_scheduler_name(mid_t mod_id);
|
||||
int flexran_set_dl_scheduler(mid_t mod_id, char *sched);
|
||||
|
||||
/* Create slice in UL, returns the new slice index */
|
||||
int flexran_create_ul_slice(mid_t mod_id, slice_id_t slice_id);
|
||||
/* Finds slice in UL with given slice_id and returns slice index */
|
||||
int flexran_find_ul_slice(mid_t mod_id, slice_id_t slice_id);
|
||||
/* Remove slice in UL */
|
||||
int flexran_remove_ul_slice(mid_t mod_id, int slice_idx);
|
||||
|
||||
/* Get the ID of a slice in UL */
|
||||
slice_id_t flexran_get_ul_slice_id(mid_t mod_id, int slice_idx);
|
||||
/* Set the ID of a slice in UL */
|
||||
void flexran_set_ul_slice_id(mid_t mod_id, int slice_idx, slice_id_t slice_id);
|
||||
|
||||
/* Get the RB share a slice in UL, value 0-100 */
|
||||
int flexran_get_ul_slice_percentage(mid_t mod_id, int slice_idx);
|
||||
/* Set the RB share a slice in UL, value 0-100 */
|
||||
void flexran_set_ul_slice_percentage(mid_t mod_id, int slice_idx, int percentage);
|
||||
|
||||
/* TODO Whether a slice in UL is isolated */
|
||||
/*int flexran_get_ul_slice_isolation(mid_t mod_id, int slice_idx);*/
|
||||
/* TODO Set whether a slice in UL is isolated */
|
||||
/*void flexran_set_ul_slice_isolation(mid_t mod_id, int slice_idx, int is_isolated);*/
|
||||
|
||||
/* TODO Get the priority of a slice in UL */
|
||||
/*int flexran_get_ul_slice_priority(mid_t mod_id, int slice_idx);*/
|
||||
/* TODO Set the priority of a slice in UL */
|
||||
/*void flexran_set_ul_slice_priority(mid_t mod_id, int slice_idx, int priority);*/
|
||||
|
||||
/* Get the first RB for allocation in a slice in UL */
|
||||
int flexran_get_ul_slice_first_rb(mid_t mod_id, int slice_idx);
|
||||
/* Set the first RB for allocation in a slice in UL */
|
||||
void flexran_set_ul_slice_first_rb(mid_t mod_id, int slice_idx, int first_rb);
|
||||
|
||||
/* TODO Get the number of RB for the allocation in a slice in UL */
|
||||
/*int flexran_get_ul_slice_length_rb(mid_t mod_id, int slice_idx);*/
|
||||
/* TODO Set the of number of RB for the allocation in a slice in UL */
|
||||
/*void flexran_set_ul_slice_length_rb(mid_t mod_id, int slice_idx, int poshigh);*/
|
||||
|
||||
/* Get the maximum MCS for slice in UL */
|
||||
int flexran_get_ul_slice_maxmcs(mid_t mod_id, int slice_idx);
|
||||
/* Set the maximum MCS for slice in UL */
|
||||
void flexran_set_ul_slice_maxmcs(mid_t mod_id, int slice_idx, int maxmcs);
|
||||
|
||||
/* TODO Get the sorting order of a slice in UL, return value is number of elements
|
||||
* in sorting_list */
|
||||
/*int flexran_get_ul_slice_sorting(mid_t mod_id, int slice_idx, Protocol__FlexUlSorting **sorting_list);*/
|
||||
/* TODO Set the sorting order of a slice in UL */
|
||||
/*void flexran_set_ul_slice_sorting(mid_t mod_id, int slice_idx, Protocol__FlexUlSorting *sorting_list, int n);*/
|
||||
|
||||
/* TODO Get the accounting policy for a slice in UL */
|
||||
/*Protocol__UlAccountingPolicy flexran_get_ul_slice_accounting_policy(mid_t mod_id, int slice_idx);*/
|
||||
/* TODO Set the accounting policy for a slice in UL */
|
||||
/*void flexran_get_ul_slice_accounting_policy(mid_t mod_id, int slice_idx, Protocol__UlAccountingPolicy accountin);*/
|
||||
|
||||
/* Get the scheduler name for a slice in UL */
|
||||
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);
|
||||
/* Get the name of/Set the UL scheduler algorithm. Same applies as for the DL
|
||||
* case */
|
||||
char *flexran_get_ul_scheduler_name(mid_t mod_id);
|
||||
int flexran_set_ul_scheduler(mid_t mod_id, char *sched);
|
||||
|
||||
/************************** S1AP **************************/
|
||||
/* Get the number of MMEs to be connected */
|
||||
@@ -832,6 +742,15 @@ int flexran_get_s1ap_mme_conf(mid_t mod_id, mid_t mme_index, Protocol__FlexS1apM
|
||||
/* Get the S1AP UE conf */
|
||||
int flexran_get_s1ap_ue(mid_t mod_id, rnti_t rnti, Protocol__FlexS1apUe * ue_conf);
|
||||
|
||||
/* Add MMEs and re-issue S1AP Registration Request */
|
||||
int flexran_add_s1ap_mme(mid_t mod_id, size_t n_mme, char **mme_ipv4);
|
||||
|
||||
/* Remove MMEs and and cut SCTP to MME */
|
||||
int flexran_remove_s1ap_mme(mid_t mod_id, size_t n_mme, char **mme_ipv4);
|
||||
|
||||
/* Set a new PLMN configuration */
|
||||
int flexran_set_new_plmn_id(mid_t mod_id, int CC_id, size_t n_plmn, Protocol__FlexPlmn **plmn_id);
|
||||
|
||||
/********************* general information *****************/
|
||||
/* get an ID for this BS (or part of a BS) */
|
||||
uint64_t flexran_get_bs_id(mid_t mod_id);
|
||||
|
||||
@@ -573,10 +573,7 @@ schedule_ue_spec(module_id_t module_idP,
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR,
|
||||
VCD_FUNCTION_IN);
|
||||
start_meas(&eNB->schedule_dlsch_preprocessor);
|
||||
dlsch_scheduler_pre_processor(module_idP,
|
||||
CC_id,
|
||||
frameP,
|
||||
subframeP);
|
||||
eNB->pre_processor_dl.dl(module_idP, CC_id, frameP, subframeP);
|
||||
stop_meas(&eNB->schedule_dlsch_preprocessor);
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR,
|
||||
VCD_FUNCTION_OUT);
|
||||
@@ -588,6 +585,7 @@ schedule_ue_spec(module_id_t module_idP,
|
||||
UE_sched_ctrl_t *ue_sched_ctrl = &UE_info->UE_sched_ctrl[UE_id];
|
||||
UE_TEMPLATE *ue_template = &UE_info->UE_template[CC_id][UE_id];
|
||||
eNB_UE_STATS *eNB_UE_stats = &UE_info->eNB_UE_stats[CC_id][UE_id];
|
||||
eNB_UE_stats->TBS = 0;
|
||||
const rnti_t rnti = ue_template->rnti;
|
||||
|
||||
// If TDD
|
||||
@@ -679,15 +677,15 @@ schedule_ue_spec(module_id_t module_idP,
|
||||
const uint32_t rbc = allocate_prbs_sub(
|
||||
nb_rb, N_RB_DL, N_RBG, ue_sched_ctrl->rballoc_sub_UE[CC_id]);
|
||||
|
||||
if (nb_rb > ue_sched_ctrl->pre_nb_available_rbs[CC_id]) {
|
||||
LOG_D(MAC,
|
||||
"[eNB %d] Frame %d CC_id %d : don't schedule UE %d, its retransmission takes more resources than we have\n",
|
||||
if (nb_rb > ue_sched_ctrl->pre_nb_available_rbs[CC_id])
|
||||
LOG_W(MAC,
|
||||
"[eNB %d] %d.%d CC_id %d : should not schedule UE %d, its "
|
||||
"retransmission takes more resources than we have\n",
|
||||
module_idP,
|
||||
frameP,
|
||||
subframeP,
|
||||
CC_id,
|
||||
UE_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* CDRX */
|
||||
ue_sched_ctrl->harq_rtt_timer[CC_id][harq_pid] = 1; // restart HARQ RTT timer
|
||||
@@ -799,6 +797,7 @@ schedule_ue_spec(module_id_t module_idP,
|
||||
eNB_UE_stats->rbs_used_retx = nb_rb;
|
||||
eNB_UE_stats->total_rbs_used_retx += nb_rb;
|
||||
eNB_UE_stats->dlsch_mcs2 = eNB_UE_stats->dlsch_mcs1;
|
||||
eNB_UE_stats->TBS = TBS;
|
||||
} else {
|
||||
// Now check RLC information to compute number of required RBs
|
||||
// get maximum TBS size for RLC request
|
||||
@@ -842,13 +841,18 @@ schedule_ue_spec(module_id_t module_idP,
|
||||
if (ue_sched_ctrl->dl_lc_bytes[i] == 0) // no data in this LC!
|
||||
continue;
|
||||
|
||||
LOG_D(MAC, "[eNB %d] SFN/SF %d.%d, LC%d->DLSCH CC_id %d, Requesting %d bytes from RLC (RRC message)\n",
|
||||
const uint32_t data =
|
||||
min(ue_sched_ctrl->dl_lc_bytes[i],
|
||||
TBS - ta_len - header_length_total - sdu_length_total - 3);
|
||||
LOG_D(MAC,
|
||||
"[eNB %d] SFN/SF %d.%d, LC%d->DLSCH CC_id %d, Requesting %d "
|
||||
"bytes from RLC (RRC message)\n",
|
||||
module_idP,
|
||||
frameP,
|
||||
subframeP,
|
||||
lcid,
|
||||
CC_id,
|
||||
TBS - ta_len - header_length_total - sdu_length_total - 3);
|
||||
data);
|
||||
|
||||
sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP,
|
||||
rnti,
|
||||
@@ -857,7 +861,7 @@ schedule_ue_spec(module_id_t module_idP,
|
||||
ENB_FLAG_YES,
|
||||
MBMS_FLAG_NO,
|
||||
lcid,
|
||||
TBS - ta_len - header_length_total - sdu_length_total - 3,
|
||||
data,
|
||||
(char *)&dlsch_buffer[sdu_length_total],
|
||||
0,
|
||||
0
|
||||
|
||||
@@ -2131,33 +2131,36 @@ dump_ue_list(UE_list_t *listP) {
|
||||
* Add a UE to UE_list listP
|
||||
*/
|
||||
inline void add_ue_list(UE_list_t *listP, int UE_id) {
|
||||
if (listP->head == -1) {
|
||||
listP->head = UE_id;
|
||||
listP->next[UE_id] = -1;
|
||||
} else {
|
||||
int i = listP->head;
|
||||
while (listP->next[i] >= 0)
|
||||
i = listP->next[i];
|
||||
listP->next[i] = UE_id;
|
||||
listP->next[UE_id] = -1;
|
||||
}
|
||||
int *cur = &listP->head;
|
||||
while (*cur >= 0)
|
||||
cur = &listP->next[*cur];
|
||||
*cur = UE_id;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
* Remove a UE from the UE_list listP, return the previous element
|
||||
* Remove a UE from the UE_list listP
|
||||
*/
|
||||
inline int remove_ue_list(UE_list_t *listP, int UE_id) {
|
||||
listP->next[UE_id] = -1;
|
||||
if (listP->head == UE_id) {
|
||||
listP->head = listP->next[UE_id];
|
||||
return -1;
|
||||
}
|
||||
int *cur = &listP->head;
|
||||
while (*cur != -1 && *cur != UE_id)
|
||||
cur = &listP->next[*cur];
|
||||
if (*cur == -1)
|
||||
return 0;
|
||||
int *next = &listP->next[*cur];
|
||||
*cur = listP->next[*cur];
|
||||
*next = -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int previous = prev(listP, UE_id);
|
||||
if (previous != -1)
|
||||
listP->next[previous] = listP->next[UE_id];
|
||||
return previous;
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
* Initialize the UE_list listP
|
||||
*/
|
||||
inline void init_ue_list(UE_list_t *listP) {
|
||||
listP->head = -1;
|
||||
for (int i = 0; i < MAX_MOBILES_PER_ENB; ++i)
|
||||
listP->next[i] = -1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -2196,6 +2199,12 @@ add_new_ue(module_id_t mod_idP,
|
||||
UE_info->active[UE_id] = TRUE;
|
||||
add_ue_list(&UE_info->list, UE_id);
|
||||
dump_ue_list(&UE_info->list);
|
||||
pp_impl_param_t* dl = &RC.mac[mod_idP]->pre_processor_dl;
|
||||
if (dl->slices) // inform slice implementation about new UE
|
||||
dl->add_UE(dl->slices, UE_id);
|
||||
pp_impl_param_t* ul = &RC.mac[mod_idP]->pre_processor_ul;
|
||||
if (ul->slices) // inform slice implementation about new UE
|
||||
ul->add_UE(ul->slices, UE_id);
|
||||
if (IS_SOFTMODEM_IQPLAYER)// not specific to record/playback ?
|
||||
UE_info->UE_template[cc_idP][UE_id].pre_assigned_mcs_ul = 0;
|
||||
UE_info->UE_template[cc_idP][UE_id].rach_resource_type = rach_resource_type;
|
||||
@@ -2259,6 +2268,12 @@ rrc_mac_remove_ue(module_id_t mod_idP,
|
||||
UE_info->num_UEs--;
|
||||
|
||||
remove_ue_list(&UE_info->list, UE_id);
|
||||
pp_impl_param_t* dl = &RC.mac[mod_idP]->pre_processor_dl;
|
||||
if (dl->slices) // inform slice implementation about new UE
|
||||
dl->remove_UE(dl->slices, UE_id);
|
||||
pp_impl_param_t* ul = &RC.mac[mod_idP]->pre_processor_ul;
|
||||
if (ul->slices) // inform slice implementation about new UE
|
||||
ul->remove_UE(ul->slices, UE_id);
|
||||
|
||||
/* Clear all remaining pending transmissions */
|
||||
memset(&UE_info->UE_template[pCC_id][UE_id], 0, sizeof(UE_TEMPLATE));
|
||||
|
||||
@@ -1301,11 +1301,11 @@ schedule_ulsch_rnti(module_id_t module_idP,
|
||||
|
||||
/*
|
||||
* ULSCH preprocessor: set UE_template->
|
||||
* pre_allocated_nb_rb_ul[slice_idx]
|
||||
* pre_allocated_nb_rb_ul
|
||||
* pre_assigned_mcs_ul
|
||||
* pre_allocated_rb_table_index_ul
|
||||
*/
|
||||
ulsch_scheduler_pre_processor(module_idP, CC_id, frameP, subframeP, sched_frame, sched_subframeP);
|
||||
mac->pre_processor_ul.ul(module_idP, CC_id, frameP, subframeP, sched_frame, sched_subframeP);
|
||||
|
||||
for (int UE_id = UE_info->list.head; UE_id >= 0; UE_id = UE_info->list.next[UE_id]) {
|
||||
if (UE_info->UE_template[CC_id][UE_id].rach_resource_type > 0)
|
||||
|
||||
+81
-105
@@ -155,9 +155,6 @@
|
||||
/*!\brief minimum MAC data needed for transmitting 1 min RLC PDU size + 1 byte MAC subHeader */
|
||||
#define MIN_MAC_HDR_RLC_SIZE (1 + MIN_RLC_PDU_SIZE)
|
||||
|
||||
/*!\brief maximum number of slices / groups */
|
||||
#define MAX_NUM_SLICES 10
|
||||
|
||||
|
||||
#define U_PLANE_INACTIVITY_VALUE 0 /* defined 10ms order (zero means infinity) */
|
||||
|
||||
@@ -543,7 +540,6 @@ typedef enum {
|
||||
SCHED_MODE_FAIR_RR /// fair raund robin
|
||||
} SCHEDULER_MODES;
|
||||
|
||||
|
||||
/*! \brief temporary struct for ULSCH sched */
|
||||
typedef struct {
|
||||
rnti_t rnti;
|
||||
@@ -1150,9 +1146,6 @@ typedef struct {
|
||||
UE_list_t list;
|
||||
int num_UEs;
|
||||
boolean_t active[MAX_MOBILES_PER_ENB];
|
||||
|
||||
/// Sorting criteria for the UE list in the MAC preprocessor
|
||||
uint16_t sorting_criteria[MAX_NUM_SLICES][CR_NUM];
|
||||
} UE_info_t;
|
||||
|
||||
/*! \brief deleting control information*/
|
||||
@@ -1171,101 +1164,6 @@ typedef struct {
|
||||
int tail_freelist; ///the tail position of the delete list
|
||||
} UE_free_list_t;
|
||||
|
||||
/**
|
||||
* slice specific scheduler for the DL
|
||||
*/
|
||||
typedef void (*slice_scheduler_dl)(module_id_t mod_id,
|
||||
int slice_idx,
|
||||
frame_t frame,
|
||||
sub_frame_t subframe,
|
||||
int *mbsfn_flag);
|
||||
|
||||
typedef struct {
|
||||
slice_id_t id;
|
||||
|
||||
/// RB share for each slice
|
||||
float pct;
|
||||
|
||||
/// whether this slice is isolated from the others
|
||||
int isol;
|
||||
|
||||
int prio;
|
||||
|
||||
/// Frequency ranges for slice positioning
|
||||
int pos_low;
|
||||
int pos_high;
|
||||
|
||||
// max mcs for each slice
|
||||
int maxmcs;
|
||||
|
||||
/// criteria for sorting policies of the slices
|
||||
uint32_t sorting;
|
||||
|
||||
/// Accounting policy (just greedy(1) or fair(0) setting for now)
|
||||
int accounting;
|
||||
|
||||
/// name of available scheduler
|
||||
char *sched_name;
|
||||
|
||||
/// pointer to the slice specific scheduler in DL
|
||||
slice_scheduler_dl sched_cb;
|
||||
|
||||
} slice_sched_conf_dl_t;
|
||||
|
||||
typedef void (*slice_scheduler_ul)(module_id_t mod_id,
|
||||
int slice_idx,
|
||||
frame_t frame,
|
||||
sub_frame_t subframe,
|
||||
unsigned char sched_subframe,
|
||||
uint16_t *first_rb);
|
||||
|
||||
typedef struct {
|
||||
slice_id_t id;
|
||||
|
||||
/// RB share for each slice
|
||||
float pct;
|
||||
|
||||
// MAX MCS for each slice
|
||||
int maxmcs;
|
||||
|
||||
/// criteria for sorting policies of the slices
|
||||
uint32_t sorting;
|
||||
|
||||
/// starting RB (RB offset) of UL scheduling
|
||||
int first_rb;
|
||||
|
||||
/// name of available scheduler
|
||||
char *sched_name;
|
||||
|
||||
/// pointer to the slice specific scheduler in UL
|
||||
slice_scheduler_ul sched_cb;
|
||||
|
||||
} slice_sched_conf_ul_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
/// counter used to indicate when all slices have pre-allocated UEs
|
||||
//int slice_counter;
|
||||
|
||||
/// indicates whether remaining RBs after first intra-slice allocation will
|
||||
/// be allocated to UEs of the same slice
|
||||
int intraslice_share_active;
|
||||
/// indicates whether remaining RBs after slice allocation will be
|
||||
/// allocated to UEs of another slice. Isolated slices will be ignored
|
||||
int interslice_share_active;
|
||||
|
||||
/// number of active DL slices
|
||||
int n_dl;
|
||||
slice_sched_conf_dl_t dl[MAX_NUM_SLICES];
|
||||
|
||||
/// number of active UL slices
|
||||
int n_ul;
|
||||
slice_sched_conf_ul_t ul[MAX_NUM_SLICES];
|
||||
|
||||
/// common rb allocation list between slices
|
||||
uint8_t rballoc_sub[NFAPI_CC_MAX][N_RBG_MAX];
|
||||
} slice_info_t;
|
||||
|
||||
/**
|
||||
* describes contiguous RBs
|
||||
*/
|
||||
@@ -1274,6 +1172,82 @@ typedef struct {
|
||||
int length;
|
||||
} contig_rbs_t;
|
||||
|
||||
/**
|
||||
* definition of a scheduling algorithm implementation used in the
|
||||
* default DL scheduler
|
||||
*/
|
||||
typedef struct {
|
||||
char *name;
|
||||
void *(*setup)(void);
|
||||
void (*unset)(void **);
|
||||
int (*run)(
|
||||
module_id_t, int, int, int, UE_list_t *, int, int, uint8_t *, void *);
|
||||
void *data;
|
||||
} default_sched_dl_algo_t;
|
||||
|
||||
/**
|
||||
* definition of a scheduling algorithm implementation used in the
|
||||
* default UL scheduler
|
||||
*/
|
||||
typedef struct {
|
||||
char *name;
|
||||
void *(*setup)(void);
|
||||
void (*unset)(void **);
|
||||
int (*run)(
|
||||
module_id_t, int, int, int, int, int, UE_list_t *, int, int, contig_rbs_t *, void *);
|
||||
void *data;
|
||||
} default_sched_ul_algo_t;
|
||||
|
||||
typedef void (*pp_impl_dl)(module_id_t mod_id,
|
||||
int CC_id,
|
||||
frame_t frame,
|
||||
sub_frame_t subframe);
|
||||
typedef void (*pp_impl_ul)(module_id_t mod_id,
|
||||
int CC_id,
|
||||
frame_t frame,
|
||||
sub_frame_t subframe,
|
||||
frame_t sched_frame,
|
||||
sub_frame_t sched_subframe);
|
||||
|
||||
struct slice_info_s;
|
||||
typedef struct {
|
||||
int algorithm;
|
||||
|
||||
/// inform the slice algorithm about a new UE
|
||||
void (*add_UE)(struct slice_info_s *s, int UE_id);
|
||||
/// inform the slice algorithm about a UE that disconnected
|
||||
void (*remove_UE)(struct slice_info_s *s, int UE_id);
|
||||
/// move a UE to a slice in DL/UL, -1 means don't move (no-op).
|
||||
void (*move_UE)(struct slice_info_s *s, int UE_id, int idx);
|
||||
|
||||
/// Adds a new slice through admission control. slice_params are
|
||||
/// algorithm-specific parameters. sched is either a default_sched_ul_algo_t
|
||||
/// or default_sched_dl_algo_t, depending on whether this implementation
|
||||
/// handles UL/DL. If slice at index exists, updates existing
|
||||
/// slice. Returns index of new slice or -1 on failure.
|
||||
int (*addmod_slice)(struct slice_info_s *s,
|
||||
int id,
|
||||
char *label,
|
||||
void *sched,
|
||||
void *slice_params);
|
||||
/// Returns slice through slice_idx. 1 if successful, 0 if not.
|
||||
int (*remove_slice)(struct slice_info_s *s, uint8_t slice_idx);
|
||||
|
||||
union {
|
||||
pp_impl_dl dl;
|
||||
pp_impl_ul ul;
|
||||
};
|
||||
|
||||
union {
|
||||
default_sched_ul_algo_t ul_algo;
|
||||
default_sched_dl_algo_t dl_algo;
|
||||
};
|
||||
|
||||
void (*destroy)(struct slice_info_s **s);
|
||||
|
||||
struct slice_info_s *slices;
|
||||
} pp_impl_param_t;
|
||||
|
||||
/*! \brief eNB common channels */
|
||||
typedef struct {
|
||||
int physCellId;
|
||||
@@ -1395,9 +1369,6 @@ typedef struct eNB_MAC_INST_s {
|
||||
uint32_t ul_handle;
|
||||
UE_info_t UE_info;
|
||||
|
||||
/// slice-related configuration
|
||||
slice_info_t slice_info;
|
||||
|
||||
///subband bitmap configuration
|
||||
SBMAP_CONF sbmap_conf;
|
||||
/// CCE table used to build DCI scheduling information
|
||||
@@ -1432,6 +1403,11 @@ typedef struct eNB_MAC_INST_s {
|
||||
UE_free_list_t UE_free_list;
|
||||
/// for scheduling selection
|
||||
SCHEDULER_MODES scheduler_mode;
|
||||
/// Default scheduler: Pre-processor implementation. Algorithms for UL/DL
|
||||
/// are called by ULSCH/DLSCH, respectively. Pro-processor implementation can
|
||||
/// encapsulate slicing.
|
||||
pp_impl_param_t pre_processor_dl;
|
||||
pp_impl_param_t pre_processor_ul;
|
||||
|
||||
int32_t puSch10xSnr;
|
||||
int32_t puCch10xSnr;
|
||||
|
||||
@@ -187,8 +187,6 @@ void add_msg3(module_id_t module_idP, int CC_id, RA_t *ra, frame_t frameP,
|
||||
|
||||
void init_UE_info(UE_info_t *UE_info);
|
||||
|
||||
void init_slice_info(slice_info_t *sli);
|
||||
|
||||
int mac_top_init(int eMBMS_active, char *uecap_xer,
|
||||
uint8_t cba_group_active, uint8_t HO_active);
|
||||
|
||||
@@ -661,6 +659,7 @@ int prev(UE_list_t *listP, int nodeP);
|
||||
void add_ue_list(UE_list_t *listP, int UE_id);
|
||||
int remove_ue_list(UE_list_t *listP, int UE_id);
|
||||
void dump_ue_list(UE_list_t *listP);
|
||||
void init_ue_list(UE_list_t *listP);
|
||||
int UE_num_active_CC(UE_info_t *listP, int ue_idP);
|
||||
int UE_PCCID(module_id_t mod_idP, int ue_idP);
|
||||
rnti_t UE_RNTI(module_id_t mod_idP, int ue_idP);
|
||||
@@ -675,10 +674,10 @@ void set_ul_DAI(int module_idP,
|
||||
|
||||
void ulsch_scheduler_pre_processor(module_id_t module_idP,
|
||||
int CC_id,
|
||||
int frameP,
|
||||
frame_t frameP,
|
||||
sub_frame_t subframeP,
|
||||
int sched_frameP,
|
||||
unsigned char sched_subframeP);
|
||||
frame_t sched_frameP,
|
||||
sub_frame_t sched_subframeP);
|
||||
|
||||
int phy_stats_exist(module_id_t Mod_id, int rnti);
|
||||
|
||||
|
||||
+17
-31
@@ -45,11 +45,8 @@ extern RAN_CONTEXT_t RC;
|
||||
|
||||
void init_UE_info(UE_info_t *UE_info)
|
||||
{
|
||||
int list_el;
|
||||
UE_info->num_UEs = 0;
|
||||
UE_info->list.head = -1;
|
||||
for (list_el = 0; list_el < MAX_MOBILES_PER_ENB; list_el++)
|
||||
UE_info->list.next[list_el] = -1;
|
||||
init_ue_list(&UE_info->list);
|
||||
memset(UE_info->DLSCH_pdu, 0, sizeof(UE_info->DLSCH_pdu));
|
||||
memset(UE_info->UE_template, 0, sizeof(UE_info->UE_template));
|
||||
memset(UE_info->eNB_UE_stats, 0, sizeof(UE_info->eNB_UE_stats));
|
||||
@@ -57,32 +54,6 @@ void init_UE_info(UE_info_t *UE_info)
|
||||
memset(UE_info->active, 0, sizeof(UE_info->active));
|
||||
}
|
||||
|
||||
void init_slice_info(slice_info_t *sli)
|
||||
{
|
||||
sli->intraslice_share_active = 1;
|
||||
sli->interslice_share_active = 1;
|
||||
|
||||
sli->n_dl = 1;
|
||||
memset(sli->dl, 0, sizeof(slice_sched_conf_dl_t) * MAX_NUM_SLICES);
|
||||
sli->dl[0].pct = 1.0;
|
||||
sli->dl[0].prio = 10;
|
||||
sli->dl[0].pos_high = N_RBG_MAX;
|
||||
sli->dl[0].maxmcs = 28;
|
||||
sli->dl[0].sorting = 0x012345;
|
||||
sli->dl[0].sched_name = "schedule_ue_spec";
|
||||
sli->dl[0].sched_cb = dlsym(NULL, sli->dl[0].sched_name);
|
||||
AssertFatal(sli->dl[0].sched_cb, "DLSCH scheduler callback is NULL\n");
|
||||
|
||||
sli->n_ul = 1;
|
||||
memset(sli->ul, 0, sizeof(slice_sched_conf_ul_t) * MAX_NUM_SLICES);
|
||||
sli->ul[0].pct = 1.0;
|
||||
sli->ul[0].maxmcs = 20;
|
||||
sli->ul[0].sorting = 0x0123;
|
||||
sli->ul[0].sched_name = "schedule_ulsch_rnti";
|
||||
sli->ul[0].sched_cb = dlsym(NULL, sli->ul[0].sched_name);
|
||||
AssertFatal(sli->ul[0].sched_cb, "ULSCH scheduler callback is NULL\n");
|
||||
}
|
||||
|
||||
void mac_top_init_eNB(void)
|
||||
{
|
||||
module_id_t i, j;
|
||||
@@ -129,8 +100,23 @@ void mac_top_init_eNB(void)
|
||||
|
||||
mac[i]->if_inst = IF_Module_init(i);
|
||||
|
||||
mac[i]->pre_processor_dl.algorithm = 0;
|
||||
mac[i]->pre_processor_dl.dl = dlsch_scheduler_pre_processor;
|
||||
char *s = "round_robin_dl";
|
||||
void *d = dlsym(NULL, s);
|
||||
AssertFatal(d, "%s(): no scheduler algo '%s' found\n", __func__, s);
|
||||
mac[i]->pre_processor_dl.dl_algo = *(default_sched_dl_algo_t *) d;
|
||||
mac[i]->pre_processor_dl.dl_algo.data = mac[i]->pre_processor_dl.dl_algo.setup();
|
||||
|
||||
mac[i]->pre_processor_ul.algorithm = 0;
|
||||
mac[i]->pre_processor_ul.ul = ulsch_scheduler_pre_processor;
|
||||
s = "round_robin_ul";
|
||||
d = dlsym(NULL, s);
|
||||
AssertFatal(d, "%s(): no scheduler algo '%s' found\n", __func__, s);
|
||||
mac[i]->pre_processor_ul.ul_algo = *(default_sched_ul_algo_t *) d;
|
||||
mac[i]->pre_processor_ul.ul_algo.data = mac[i]->pre_processor_ul.ul_algo.setup();
|
||||
|
||||
init_UE_info(&mac[i]->UE_info);
|
||||
init_slice_info(&mac[i]->slice_info);
|
||||
}
|
||||
|
||||
RC.mac = mac;
|
||||
|
||||
+475
-154
@@ -69,31 +69,367 @@ int get_rbg_size_last(module_id_t Mod_id, int CC_id) {
|
||||
return RBGsize;
|
||||
}
|
||||
|
||||
int g_start_ue_dl = -1;
|
||||
int round_robin_dl(module_id_t Mod_id,
|
||||
int CC_id,
|
||||
int frame,
|
||||
int subframe,
|
||||
UE_list_t *UE_list,
|
||||
int max_num_ue,
|
||||
int n_rbg_sched,
|
||||
uint8_t *rbgalloc_mask) {
|
||||
void *rr_dl_setup(void) {
|
||||
void *data = malloc(sizeof(int));
|
||||
*(int *) data = 0;
|
||||
AssertFatal(data, "could not allocate data in %s()\n", __func__);
|
||||
return data;
|
||||
}
|
||||
void rr_dl_unset(void **data) {
|
||||
if (*data)
|
||||
free(*data);
|
||||
*data = NULL;
|
||||
}
|
||||
int rr_dl_run(module_id_t Mod_id,
|
||||
int CC_id,
|
||||
int frame,
|
||||
int subframe,
|
||||
UE_list_t *UE_list,
|
||||
int max_num_ue,
|
||||
int n_rbg_sched,
|
||||
uint8_t *rbgalloc_mask,
|
||||
void *data) {
|
||||
DevAssert(UE_list->head >= 0);
|
||||
DevAssert(n_rbg_sched > 0);
|
||||
const int N_RBG = to_rbg(RC.mac[Mod_id]->common_channels[CC_id].mib->message.dl_Bandwidth);
|
||||
const int RBGsize = get_min_rb_unit(Mod_id, CC_id);
|
||||
const int RBGlastsize = get_rbg_size_last(Mod_id, CC_id);
|
||||
int num_ue_req = 0;
|
||||
UE_info_t *UE_info = &RC.mac[Mod_id]->UE_info;
|
||||
|
||||
int rb_required[MAX_MOBILES_PER_ENB]; // how much UEs request
|
||||
memset(rb_required, 0, sizeof(rb_required));
|
||||
|
||||
int rbg = 0;
|
||||
for (; !rbgalloc_mask[rbg]; rbg++)
|
||||
; /* fast-forward to first allowed RBG */
|
||||
|
||||
// Calculate the amount of RBs every UE wants to send.
|
||||
/* just start with the UE after the one we had last time. If it does not
|
||||
* exist, this will start at the head */
|
||||
int *start_ue = data;
|
||||
*start_ue = next_ue_list_looped(UE_list, *start_ue);
|
||||
|
||||
int UE_id = *start_ue;
|
||||
UE_list_t UE_sched;
|
||||
int *cur_UE = &UE_sched.head;
|
||||
// Allocate retransmissions, and mark UEs with new transmissions
|
||||
do {
|
||||
// check whether there are HARQ retransmissions
|
||||
const COMMON_channels_t *cc = &RC.mac[Mod_id]->common_channels[CC_id];
|
||||
const uint8_t harq_pid = frame_subframe2_dl_harq_pid(cc->tdd_Config, frame, subframe);
|
||||
UE_sched_ctrl_t *ue_ctrl = &UE_info->UE_sched_ctrl[UE_id];
|
||||
const uint8_t round = ue_ctrl->round[CC_id][harq_pid];
|
||||
if (round != 8) { // retransmission: allocate
|
||||
const int nb_rb = UE_info->UE_template[CC_id][UE_id].nb_rb[harq_pid];
|
||||
if (nb_rb == 0)
|
||||
goto skip_ue;
|
||||
int nb_rbg = (nb_rb + (nb_rb % RBGsize)) / RBGsize;
|
||||
// needs more RBGs than we can allocate
|
||||
if (nb_rbg > n_rbg_sched) {
|
||||
LOG_D(MAC,
|
||||
"retransmission of UE %d needs more RBGs (%d) than we have (%d)\n",
|
||||
UE_id, nb_rbg, n_rbg_sched);
|
||||
goto skip_ue;
|
||||
}
|
||||
// ensure that the number of RBs can be contained by the RBGs (!), i.e.
|
||||
// if we allocate the last RBG this one should have the full RBGsize
|
||||
if ((nb_rb % RBGsize) == 0 && nb_rbg == n_rbg_sched
|
||||
&& rbgalloc_mask[N_RBG - 1] && RBGlastsize != RBGsize) {
|
||||
LOG_D(MAC,
|
||||
"retransmission of UE %d needs %d RBs, but the last RBG %d is too small (%d, normal %d)\n",
|
||||
UE_id, nb_rb, N_RBG - 1, RBGlastsize, RBGsize);
|
||||
goto skip_ue;
|
||||
}
|
||||
const uint8_t cqi = ue_ctrl->dl_cqi[CC_id];
|
||||
const int idx = CCE_try_allocate_dlsch(Mod_id, CC_id, subframe, UE_id, cqi);
|
||||
if (idx < 0)
|
||||
goto skip_ue; // cannot allocate CCE
|
||||
ue_ctrl->pre_dci_dl_pdu_idx = idx;
|
||||
// retransmissions: directly allocate
|
||||
n_rbg_sched -= nb_rbg;
|
||||
ue_ctrl->pre_nb_available_rbs[CC_id] += nb_rb;
|
||||
for (; nb_rbg > 0; rbg++) {
|
||||
if (!rbgalloc_mask[rbg])
|
||||
continue;
|
||||
ue_ctrl->rballoc_sub_UE[CC_id][rbg] = 1;
|
||||
rbgalloc_mask[rbg] = 0;
|
||||
nb_rbg--;
|
||||
}
|
||||
LOG_D(MAC,
|
||||
"%4d.%d n_rbg_sched %d after retransmission reservation for UE %d "
|
||||
"round %d retx nb_rb %d pre_nb_available_rbs %d\n",
|
||||
frame, subframe, n_rbg_sched, UE_id, round,
|
||||
UE_info->UE_template[CC_id][UE_id].nb_rb[harq_pid],
|
||||
ue_ctrl->pre_nb_available_rbs[CC_id]);
|
||||
/* if there are no more RBG to give, return */
|
||||
if (n_rbg_sched <= 0)
|
||||
return 0;
|
||||
max_num_ue--;
|
||||
/* if there are no UEs that can be allocated anymore, return */
|
||||
if (max_num_ue == 0)
|
||||
return n_rbg_sched;
|
||||
for (; !rbgalloc_mask[rbg]; rbg++) /* fast-forward */ ;
|
||||
} else {
|
||||
if (UE_info->UE_template[CC_id][UE_id].dl_buffer_total > 0) {
|
||||
*cur_UE = UE_id;
|
||||
cur_UE = &UE_sched.next[UE_id];
|
||||
}
|
||||
}
|
||||
|
||||
skip_ue:
|
||||
UE_id = next_ue_list_looped(UE_list, UE_id);
|
||||
} while (UE_id != *start_ue);
|
||||
*cur_UE = -1; // mark end
|
||||
|
||||
if (UE_sched.head < 0)
|
||||
return n_rbg_sched; // no UE has a transmission
|
||||
|
||||
// after allocating retransmissions: pre-allocate CCE, compute number of
|
||||
// requested RBGs
|
||||
max_num_ue = min(max_num_ue, n_rbg_sched);
|
||||
int rb_required[MAX_MOBILES_PER_ENB]; // how much UEs request
|
||||
cur_UE = &UE_sched.head;
|
||||
while (*cur_UE >= 0 && max_num_ue > 0) {
|
||||
const int UE_id = *cur_UE;
|
||||
cur_UE = &UE_sched.next[UE_id]; // go to next
|
||||
const uint8_t cqi = UE_info->UE_sched_ctrl[UE_id].dl_cqi[CC_id];
|
||||
const int idx = CCE_try_allocate_dlsch(Mod_id, CC_id, subframe, UE_id, cqi);
|
||||
if (idx < 0) {
|
||||
LOG_D(MAC, "cannot allocate CCE for UE %d, skipping\n", UE_id);
|
||||
continue;
|
||||
}
|
||||
UE_info->UE_sched_ctrl[UE_id].pre_dci_dl_pdu_idx = idx;
|
||||
const int mcs = cqi_to_mcs[cqi];
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1 = mcs;
|
||||
const uint32_t B = UE_info->UE_template[CC_id][UE_id].dl_buffer_total;
|
||||
rb_required[UE_id] = find_nb_rb_DL(mcs, B, n_rbg_sched * RBGsize, RBGsize);
|
||||
max_num_ue--;
|
||||
}
|
||||
*cur_UE = -1; // not all UEs might be allocated, mark end
|
||||
|
||||
/* for one UE after the next: allocate resources */
|
||||
cur_UE = &UE_sched.head;
|
||||
while (*cur_UE >= 0) {
|
||||
const int UE_id = *cur_UE;
|
||||
UE_sched_ctrl_t *ue_ctrl = &UE_info->UE_sched_ctrl[UE_id];
|
||||
ue_ctrl->rballoc_sub_UE[CC_id][rbg] = 1;
|
||||
rbgalloc_mask[rbg] = 0;
|
||||
const int sRBG = rbg == N_RBG - 1 ? RBGlastsize : RBGsize;
|
||||
ue_ctrl->pre_nb_available_rbs[CC_id] += sRBG;
|
||||
rb_required[UE_id] -= sRBG;
|
||||
if (rb_required[UE_id] <= 0) {
|
||||
*cur_UE = UE_sched.next[*cur_UE];
|
||||
if (*cur_UE < 0)
|
||||
cur_UE = &UE_sched.head;
|
||||
} else {
|
||||
cur_UE = UE_sched.next[*cur_UE] < 0 ? &UE_sched.head : &UE_sched.next[*cur_UE];
|
||||
}
|
||||
n_rbg_sched--;
|
||||
if (n_rbg_sched <= 0)
|
||||
break;
|
||||
for (rbg++; !rbgalloc_mask[rbg]; rbg++) /* fast-forward */ ;
|
||||
}
|
||||
|
||||
return n_rbg_sched;
|
||||
}
|
||||
default_sched_dl_algo_t round_robin_dl = {
|
||||
.name = "round_robin_dl",
|
||||
.setup = rr_dl_setup,
|
||||
.unset = rr_dl_unset,
|
||||
.run = rr_dl_run,
|
||||
.data = NULL
|
||||
};
|
||||
|
||||
|
||||
void *pf_dl_setup(void) {
|
||||
void *data = calloc(MAX_MOBILES_PER_ENB, sizeof(float));
|
||||
for (int i = 0; i < MAX_MOBILES_PER_ENB; i++)
|
||||
*(float *) data = 0.0f;
|
||||
AssertFatal(data, "could not allocate data in %s()\n", __func__);
|
||||
return data;
|
||||
}
|
||||
void pf_dl_unset(void **data) {
|
||||
if (*data)
|
||||
free(*data);
|
||||
*data = NULL;
|
||||
}
|
||||
int pf_wbcqi_dl_run(module_id_t Mod_id,
|
||||
int CC_id,
|
||||
int frame,
|
||||
int subframe,
|
||||
UE_list_t *UE_list,
|
||||
int max_num_ue,
|
||||
int n_rbg_sched,
|
||||
uint8_t *rbgalloc_mask,
|
||||
void *data) {
|
||||
DevAssert(UE_list->head >= 0);
|
||||
DevAssert(n_rbg_sched > 0);
|
||||
const int N_RBG = to_rbg(RC.mac[Mod_id]->common_channels[CC_id].mib->message.dl_Bandwidth);
|
||||
const int RBGsize = get_min_rb_unit(Mod_id, CC_id);
|
||||
const int RBGlastsize = get_rbg_size_last(Mod_id, CC_id);
|
||||
UE_info_t *UE_info = &RC.mac[Mod_id]->UE_info;
|
||||
|
||||
int rbg = 0;
|
||||
for (; !rbgalloc_mask[rbg]; rbg++)
|
||||
; /* fast-forward to first allowed RBG */
|
||||
|
||||
UE_list_t UE_sched; // UEs that could be scheduled
|
||||
int *uep = &UE_sched.head;
|
||||
float *thr_ue = data;
|
||||
float coeff_ue[MAX_MOBILES_PER_ENB];
|
||||
|
||||
for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) {
|
||||
const float a = 0.0005f; // corresponds to 200ms window
|
||||
const uint32_t b = UE_info->eNB_UE_stats[CC_id][UE_id].TBS;
|
||||
thr_ue[UE_id] = (1 - a) * thr_ue[UE_id] + a * b;
|
||||
|
||||
// check whether there are HARQ retransmissions
|
||||
const COMMON_channels_t *cc = &RC.mac[Mod_id]->common_channels[CC_id];
|
||||
const uint8_t harq_pid = frame_subframe2_dl_harq_pid(cc->tdd_Config, frame, subframe);
|
||||
UE_sched_ctrl_t *ue_ctrl = &UE_info->UE_sched_ctrl[UE_id];
|
||||
const uint8_t round = ue_ctrl->round[CC_id][harq_pid];
|
||||
if (round != 8) { // retransmission: allocate
|
||||
const int nb_rb = UE_info->UE_template[CC_id][UE_id].nb_rb[harq_pid];
|
||||
if (nb_rb == 0)
|
||||
continue;
|
||||
int nb_rbg = (nb_rb + (nb_rb % RBGsize)) / RBGsize;
|
||||
// needs more RBGs than we can allocate
|
||||
if (nb_rbg > n_rbg_sched) {
|
||||
LOG_D(MAC,
|
||||
"retransmission of UE %d needs more RBGs (%d) than we have (%d)\n",
|
||||
UE_id, nb_rbg, n_rbg_sched);
|
||||
continue;
|
||||
}
|
||||
// ensure that the number of RBs can be contained by the RBGs (!), i.e.
|
||||
// if we allocate the last RBG this one should have the full RBGsize
|
||||
if ((nb_rb % RBGsize) == 0 && nb_rbg == n_rbg_sched
|
||||
&& rbgalloc_mask[N_RBG - 1] && RBGlastsize != RBGsize) {
|
||||
LOG_D(MAC,
|
||||
"retransmission of UE %d needs %d RBs, but the last RBG %d is too small (%d, normal %d)\n",
|
||||
UE_id, nb_rb, N_RBG - 1, RBGlastsize, RBGsize);
|
||||
continue;
|
||||
}
|
||||
const uint8_t cqi = ue_ctrl->dl_cqi[CC_id];
|
||||
const int idx = CCE_try_allocate_dlsch(Mod_id, CC_id, subframe, UE_id, cqi);
|
||||
if (idx < 0)
|
||||
continue; // cannot allocate CCE
|
||||
ue_ctrl->pre_dci_dl_pdu_idx = idx;
|
||||
// retransmissions: directly allocate
|
||||
n_rbg_sched -= nb_rbg;
|
||||
ue_ctrl->pre_nb_available_rbs[CC_id] += nb_rb;
|
||||
for (; nb_rbg > 0; rbg++) {
|
||||
if (!rbgalloc_mask[rbg])
|
||||
continue;
|
||||
ue_ctrl->rballoc_sub_UE[CC_id][rbg] = 1;
|
||||
rbgalloc_mask[rbg] = 0;
|
||||
nb_rbg--;
|
||||
}
|
||||
LOG_D(MAC,
|
||||
"%4d.%d n_rbg_sched %d after retransmission reservation for UE %d "
|
||||
"round %d retx nb_rb %d pre_nb_available_rbs %d\n",
|
||||
frame, subframe, n_rbg_sched, UE_id, round,
|
||||
UE_info->UE_template[CC_id][UE_id].nb_rb[harq_pid],
|
||||
ue_ctrl->pre_nb_available_rbs[CC_id]);
|
||||
/* if there are no more RBG to give, return */
|
||||
if (n_rbg_sched <= 0)
|
||||
return 0;
|
||||
max_num_ue--;
|
||||
/* if there are no UEs that can be allocated anymore, return */
|
||||
if (max_num_ue == 0)
|
||||
return n_rbg_sched;
|
||||
for (; !rbgalloc_mask[rbg]; rbg++) /* fast-forward */ ;
|
||||
} else {
|
||||
if (UE_info->UE_template[CC_id][UE_id].dl_buffer_total == 0)
|
||||
continue;
|
||||
|
||||
const int mcs = cqi_to_mcs[UE_info->UE_sched_ctrl[UE_id].dl_cqi[CC_id]];
|
||||
const uint32_t tbs = get_TBS_DL(mcs, RBGsize);
|
||||
coeff_ue[UE_id] = (float) tbs / thr_ue[UE_id];
|
||||
//LOG_I(MAC, " pf UE %d: old TBS %d thr %f MCS %d TBS %d coeff %f\n",
|
||||
// UE_id, b, thr_ue[UE_id], mcs, tbs, coeff_ue[UE_id]);
|
||||
*uep = UE_id;
|
||||
uep = &UE_sched.next[UE_id];
|
||||
}
|
||||
}
|
||||
*uep = -1;
|
||||
|
||||
while (max_num_ue > 0 && n_rbg_sched > 0 && UE_sched.head >= 0) {
|
||||
int *max = &UE_sched.head; /* assume head is max */
|
||||
int *p = &UE_sched.next[*max];
|
||||
while (*p >= 0) {
|
||||
/* if the current one has larger coeff, save for later */
|
||||
if (coeff_ue[*p] > coeff_ue[*max])
|
||||
max = p;
|
||||
p = &UE_sched.next[*p];
|
||||
}
|
||||
/* remove the max one */
|
||||
const int UE_id = *max;
|
||||
p = &UE_sched.next[*max];
|
||||
*max = UE_sched.next[*max];
|
||||
*p = -1;
|
||||
|
||||
const uint8_t cqi = UE_info->UE_sched_ctrl[UE_id].dl_cqi[CC_id];
|
||||
const int idx = CCE_try_allocate_dlsch(Mod_id, CC_id, subframe, UE_id, cqi);
|
||||
if (idx < 0)
|
||||
continue;
|
||||
UE_info->UE_sched_ctrl[UE_id].pre_dci_dl_pdu_idx = idx;
|
||||
|
||||
max_num_ue--;
|
||||
|
||||
/* allocate as much as possible */
|
||||
const int mcs = cqi_to_mcs[cqi];
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1 = mcs;
|
||||
int req = find_nb_rb_DL(mcs,
|
||||
UE_info->UE_template[CC_id][UE_id].dl_buffer_total,
|
||||
n_rbg_sched * RBGsize,
|
||||
RBGsize);
|
||||
UE_sched_ctrl_t *ue_ctrl = &UE_info->UE_sched_ctrl[UE_id];
|
||||
while (req > 0 && n_rbg_sched > 0) {
|
||||
ue_ctrl->rballoc_sub_UE[CC_id][rbg] = 1;
|
||||
rbgalloc_mask[rbg] = 0;
|
||||
const int sRBG = rbg == N_RBG - 1 ? RBGlastsize : RBGsize;
|
||||
ue_ctrl->pre_nb_available_rbs[CC_id] += sRBG;
|
||||
req -= sRBG;
|
||||
n_rbg_sched--;
|
||||
for (rbg++; n_rbg_sched > 0 && !rbgalloc_mask[rbg]; rbg++) /* fast-forward */ ;
|
||||
}
|
||||
}
|
||||
|
||||
return n_rbg_sched;
|
||||
}
|
||||
default_sched_dl_algo_t proportional_fair_wbcqi_dl = {
|
||||
.name = "proportional_fair_wbcqi_dl",
|
||||
.setup = pf_dl_setup,
|
||||
.unset = pf_dl_unset,
|
||||
.run = pf_wbcqi_dl_run,
|
||||
.data = NULL
|
||||
};
|
||||
|
||||
void *mt_dl_setup(void) {
|
||||
return NULL;
|
||||
}
|
||||
void mt_dl_unset(void **data) {
|
||||
*data = NULL;
|
||||
}
|
||||
int mt_wbcqi_dl_run(module_id_t Mod_id,
|
||||
int CC_id,
|
||||
int frame,
|
||||
int subframe,
|
||||
UE_list_t *UE_list,
|
||||
int max_num_ue,
|
||||
int n_rbg_sched,
|
||||
uint8_t *rbgalloc_mask,
|
||||
void *data) {
|
||||
DevAssert(UE_list->head >= 0);
|
||||
DevAssert(n_rbg_sched > 0);
|
||||
const int N_RBG = to_rbg(RC.mac[Mod_id]->common_channels[CC_id].mib->message.dl_Bandwidth);
|
||||
const int RBGsize = get_min_rb_unit(Mod_id, CC_id);
|
||||
const int RBGlastsize = get_rbg_size_last(Mod_id, CC_id);
|
||||
UE_info_t *UE_info = &RC.mac[Mod_id]->UE_info;
|
||||
|
||||
int rbg = 0;
|
||||
for (; !rbgalloc_mask[rbg]; rbg++)
|
||||
; /* fast-forward to first allowed RBG */
|
||||
|
||||
UE_list_t UE_sched; // UEs that could be scheduled
|
||||
int *uep = &UE_sched.head;
|
||||
|
||||
for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) {
|
||||
// check whether there are HARQ retransmissions
|
||||
const COMMON_channels_t *cc = &RC.mac[Mod_id]->common_channels[CC_id];
|
||||
@@ -133,6 +469,7 @@ int round_robin_dl(module_id_t Mod_id,
|
||||
if (!rbgalloc_mask[rbg])
|
||||
continue;
|
||||
ue_ctrl->rballoc_sub_UE[CC_id][rbg] = 1;
|
||||
rbgalloc_mask[rbg] = 0;
|
||||
nb_rbg--;
|
||||
}
|
||||
LOG_D(MAC,
|
||||
@@ -150,90 +487,69 @@ int round_robin_dl(module_id_t Mod_id,
|
||||
return n_rbg_sched;
|
||||
for (; !rbgalloc_mask[rbg]; rbg++) /* fast-forward */ ;
|
||||
} else {
|
||||
const int dlsch_mcs1 = cqi_to_mcs[UE_info->UE_sched_ctrl[UE_id].dl_cqi[CC_id]];
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1 = dlsch_mcs1;
|
||||
rb_required[UE_id] =
|
||||
find_nb_rb_DL(dlsch_mcs1,
|
||||
UE_info->UE_template[CC_id][UE_id].dl_buffer_total,
|
||||
n_rbg_sched * RBGsize,
|
||||
RBGsize);
|
||||
if (rb_required[UE_id] > 0)
|
||||
num_ue_req++;
|
||||
LOG_D(MAC,
|
||||
"%d/%d UE_id %d rb_required %d n_rbg_sched %d\n",
|
||||
frame,
|
||||
subframe,
|
||||
UE_id,
|
||||
rb_required[UE_id],
|
||||
n_rbg_sched);
|
||||
if (UE_info->UE_template[CC_id][UE_id].dl_buffer_total == 0)
|
||||
continue;
|
||||
*uep = UE_id;
|
||||
uep = &UE_sched.next[UE_id];
|
||||
}
|
||||
}
|
||||
*uep = -1;
|
||||
|
||||
if (num_ue_req == 0)
|
||||
return n_rbg_sched; // no UE has a transmission
|
||||
while (max_num_ue > 0 && n_rbg_sched > 0 && UE_sched.head >= 0) {
|
||||
int *max = &UE_sched.head; /* assume head is max */
|
||||
int *p = &UE_sched.next[*max];
|
||||
while (*p >= 0) {
|
||||
/* if the current one has better CQI, or the same and more data */
|
||||
const uint8_t maxCqi = UE_info->UE_sched_ctrl[*max].dl_cqi[CC_id];
|
||||
const uint32_t maxB = UE_info->UE_template[CC_id][*max].dl_buffer_total;
|
||||
const uint8_t pCqi = UE_info->UE_sched_ctrl[*p].dl_cqi[CC_id];
|
||||
const uint32_t pB = UE_info->UE_template[CC_id][*p].dl_buffer_total;
|
||||
if (pCqi > maxCqi || (pCqi == maxCqi && pB > maxB))
|
||||
max = p;
|
||||
p = &UE_sched.next[*p];
|
||||
}
|
||||
/* remove the max one */
|
||||
const int UE_id = *max;
|
||||
p = &UE_sched.next[*max];
|
||||
*max = UE_sched.next[*max];
|
||||
*p = -1;
|
||||
|
||||
// after allocating retransmissions: build list of UE to allocate.
|
||||
// if start_UE does not exist anymore (detach etc), start at first UE
|
||||
if (g_start_ue_dl == -1)
|
||||
g_start_ue_dl = UE_list->head;
|
||||
int UE_id = g_start_ue_dl;
|
||||
UE_list_t UE_sched;
|
||||
int rb_required_total = 0;
|
||||
int num_ue_sched = 0;
|
||||
max_num_ue = min(min(max_num_ue, num_ue_req), n_rbg_sched);
|
||||
int *cur_UE = &UE_sched.head;
|
||||
while (num_ue_sched < max_num_ue) {
|
||||
while (rb_required[UE_id] == 0)
|
||||
UE_id = next_ue_list_looped(UE_list, UE_id);
|
||||
const uint8_t cqi = UE_info->UE_sched_ctrl[UE_id].dl_cqi[CC_id];
|
||||
const int idx = CCE_try_allocate_dlsch(Mod_id, CC_id, subframe, UE_id, cqi);
|
||||
if (idx < 0) {
|
||||
LOG_D(MAC, "cannot allocate CCE for UE %d, skipping\n", UE_id);
|
||||
num_ue_req--;
|
||||
max_num_ue = min(min(max_num_ue, num_ue_req), n_rbg_sched);
|
||||
UE_id = next_ue_list_looped(UE_list, UE_id); // next candidate
|
||||
if (idx < 0)
|
||||
continue;
|
||||
}
|
||||
UE_info->UE_sched_ctrl[UE_id].pre_dci_dl_pdu_idx = idx;
|
||||
*cur_UE = UE_id;
|
||||
cur_UE = &UE_sched.next[UE_id];
|
||||
rb_required_total += rb_required[UE_id];
|
||||
num_ue_sched++;
|
||||
UE_id = next_ue_list_looped(UE_list, UE_id); // next candidate
|
||||
}
|
||||
*cur_UE = -1;
|
||||
|
||||
/* for one UE after the next: allocate resources */
|
||||
for (int UE_id = UE_sched.head; UE_id >= 0;
|
||||
UE_id = next_ue_list_looped(&UE_sched, UE_id)) {
|
||||
if (rb_required[UE_id] <= 0)
|
||||
continue;
|
||||
max_num_ue--;
|
||||
|
||||
/* allocate as much as possible */
|
||||
const int mcs = cqi_to_mcs[cqi];
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1 = mcs;
|
||||
int req = find_nb_rb_DL(mcs,
|
||||
UE_info->UE_template[CC_id][UE_id].dl_buffer_total,
|
||||
n_rbg_sched * RBGsize,
|
||||
RBGsize);
|
||||
UE_sched_ctrl_t *ue_ctrl = &UE_info->UE_sched_ctrl[UE_id];
|
||||
ue_ctrl->rballoc_sub_UE[CC_id][rbg] = 1;
|
||||
const int sRBG = rbg == N_RBG - 1 ? RBGlastsize : RBGsize;
|
||||
ue_ctrl->pre_nb_available_rbs[CC_id] += sRBG;
|
||||
rb_required[UE_id] -= sRBG;
|
||||
rb_required_total -= sRBG;
|
||||
if (rb_required_total <= 0)
|
||||
break;
|
||||
n_rbg_sched--;
|
||||
if (n_rbg_sched <= 0)
|
||||
break;
|
||||
for (rbg++; !rbgalloc_mask[rbg]; rbg++) /* fast-forward */ ;
|
||||
}
|
||||
|
||||
/* if not all UEs could be allocated in this round */
|
||||
if (num_ue_req > max_num_ue) {
|
||||
/* go to the first one we missed */
|
||||
for (int i = 0; i < max_num_ue; ++i)
|
||||
g_start_ue_dl = next_ue_list_looped(UE_list, g_start_ue_dl);
|
||||
} else {
|
||||
/* else, just start with the next UE next time */
|
||||
g_start_ue_dl = next_ue_list_looped(UE_list, g_start_ue_dl);
|
||||
while (req > 0 && n_rbg_sched > 0) {
|
||||
ue_ctrl->rballoc_sub_UE[CC_id][rbg] = 1;
|
||||
rbgalloc_mask[rbg] = 0;
|
||||
const int sRBG = rbg == N_RBG - 1 ? RBGlastsize : RBGsize;
|
||||
ue_ctrl->pre_nb_available_rbs[CC_id] += sRBG;
|
||||
req -= sRBG;
|
||||
n_rbg_sched--;
|
||||
for (rbg++; n_rbg_sched > 0 && !rbgalloc_mask[rbg]; rbg++) /* fast-forward */ ;
|
||||
}
|
||||
}
|
||||
|
||||
return n_rbg_sched;
|
||||
}
|
||||
default_sched_dl_algo_t maximum_throughput_wbcqi_dl = {
|
||||
.name = "maximum_throughput_wbcqi_dl",
|
||||
.setup = mt_dl_setup,
|
||||
.unset = mt_dl_unset,
|
||||
.run = mt_wbcqi_dl_run,
|
||||
.data = NULL
|
||||
};
|
||||
|
||||
// This function stores the downlink buffer for all the logical channels
|
||||
void
|
||||
@@ -323,19 +639,18 @@ dlsch_scheduler_pre_processor(module_id_t Mod_id,
|
||||
int CC_id,
|
||||
frame_t frameP,
|
||||
sub_frame_t subframeP) {
|
||||
UE_info_t *UE_info = &RC.mac[Mod_id]->UE_info;
|
||||
const int N_RBG = to_rbg(RC.mac[Mod_id]->common_channels[CC_id].mib->message.dl_Bandwidth);
|
||||
eNB_MAC_INST *mac = RC.mac[Mod_id];
|
||||
UE_info_t *UE_info = &mac->UE_info;
|
||||
const int N_RBG = to_rbg(mac->common_channels[CC_id].mib->message.dl_Bandwidth);
|
||||
const int RBGsize = get_min_rb_unit(Mod_id, CC_id);
|
||||
|
||||
store_dlsch_buffer(Mod_id, CC_id, frameP, subframeP);
|
||||
|
||||
UE_list_t UE_to_sched;
|
||||
UE_to_sched.head = -1;
|
||||
for (int i = 0; i < MAX_MOBILES_PER_ENB; ++i)
|
||||
UE_to_sched.next[i] = -1;
|
||||
int *cur = &UE_to_sched.head;
|
||||
|
||||
int first = 1;
|
||||
int last_UE_id = -1;
|
||||
for (int UE_id = UE_info->list.head; UE_id >= 0; UE_id = UE_info->list.next[UE_id]) {
|
||||
UE_sched_ctrl_t *ue_sched_ctrl = &UE_info->UE_sched_ctrl[UE_id];
|
||||
const UE_TEMPLATE *ue_template = &UE_info->UE_template[CC_id][UE_id];
|
||||
@@ -368,20 +683,15 @@ dlsch_scheduler_pre_processor(module_id_t Mod_id,
|
||||
}
|
||||
|
||||
/* define UEs to schedule */
|
||||
if (first) {
|
||||
first = 0;
|
||||
UE_to_sched.head = UE_id;
|
||||
} else {
|
||||
UE_to_sched.next[last_UE_id] = UE_id;
|
||||
}
|
||||
UE_to_sched.next[UE_id] = -1;
|
||||
last_UE_id = UE_id;
|
||||
*cur = UE_id;
|
||||
cur = &UE_to_sched.next[UE_id];
|
||||
}
|
||||
*cur = -1;
|
||||
|
||||
if (UE_to_sched.head < 0)
|
||||
return;
|
||||
|
||||
uint8_t *vrb_map = RC.mac[Mod_id]->common_channels[CC_id].vrb_map;
|
||||
uint8_t *vrb_map = mac->common_channels[CC_id].vrb_map;
|
||||
uint8_t rbgalloc_mask[N_RBG_MAX];
|
||||
int n_rbg_sched = 0;
|
||||
for (int i = 0; i < N_RBG; i++) {
|
||||
@@ -393,14 +703,15 @@ dlsch_scheduler_pre_processor(module_id_t Mod_id,
|
||||
n_rbg_sched += rbgalloc_mask[i];
|
||||
}
|
||||
|
||||
round_robin_dl(Mod_id,
|
||||
CC_id,
|
||||
frameP,
|
||||
subframeP,
|
||||
&UE_to_sched,
|
||||
4, // max_num_ue
|
||||
n_rbg_sched,
|
||||
rbgalloc_mask);
|
||||
mac->pre_processor_dl.dl_algo.run(Mod_id,
|
||||
CC_id,
|
||||
frameP,
|
||||
subframeP,
|
||||
&UE_to_sched,
|
||||
4, // max_num_ue
|
||||
n_rbg_sched,
|
||||
rbgalloc_mask,
|
||||
mac->pre_processor_dl.dl_algo.data);
|
||||
|
||||
// the following block is meant for validation of the pre-processor to check
|
||||
// whether all UE allocations are non-overlapping and is not necessary for
|
||||
@@ -512,17 +823,28 @@ int pp_find_rb_table_index(int approximate) {
|
||||
return p + 1;
|
||||
}
|
||||
|
||||
int g_start_ue_ul = -1;
|
||||
int round_robin_ul(module_id_t Mod_id,
|
||||
int CC_id,
|
||||
int frame,
|
||||
int subframe,
|
||||
int sched_frame,
|
||||
int sched_subframe,
|
||||
UE_list_t *UE_list,
|
||||
int max_num_ue,
|
||||
int num_contig_rb,
|
||||
contig_rbs_t *rbs) {
|
||||
void *rr_ul_setup(void) {
|
||||
void *data = malloc(sizeof(int));
|
||||
*(int *) data = 0;
|
||||
AssertFatal(data, "could not allocate data in %s()\n", __func__);
|
||||
return data;
|
||||
}
|
||||
void rr_ul_unset(void **data) {
|
||||
if (*data)
|
||||
free(*data);
|
||||
*data = NULL;
|
||||
}
|
||||
int rr_ul_run(module_id_t Mod_id,
|
||||
int CC_id,
|
||||
int frame,
|
||||
int subframe,
|
||||
int sched_frame,
|
||||
int sched_subframe,
|
||||
UE_list_t *UE_list,
|
||||
int max_num_ue,
|
||||
int num_contig_rb,
|
||||
contig_rbs_t *rbs,
|
||||
void *data) {
|
||||
AssertFatal(num_contig_rb <= 2, "cannot handle more than two contiguous RB regions\n");
|
||||
UE_info_t *UE_info = &RC.mac[Mod_id]->UE_info;
|
||||
const int max_rb = num_contig_rb > 1 ? MAX(rbs[0].length, rbs[1].length) : rbs[0].length;
|
||||
@@ -662,9 +984,10 @@ int round_robin_ul(module_id_t Mod_id,
|
||||
end = la > lb ? 2 : -1;
|
||||
}
|
||||
|
||||
if (g_start_ue_ul == -1)
|
||||
g_start_ue_ul = UE_list->head;
|
||||
int sUE_id = g_start_ue_ul;
|
||||
int *start_ue = data;
|
||||
if (*start_ue == -1)
|
||||
*start_ue = UE_list->head;
|
||||
int sUE_id = *start_ue;
|
||||
int rb_idx_given[MAX_MOBILES_PER_ENB];
|
||||
memset(rb_idx_given, 0, sizeof(rb_idx_given));
|
||||
|
||||
@@ -742,35 +1065,35 @@ int round_robin_ul(module_id_t Mod_id,
|
||||
}
|
||||
}
|
||||
|
||||
/* if not all UEs could be allocated in this round */
|
||||
if (num_ue_req > max_num_ue) {
|
||||
/* go to the first one we missed */
|
||||
for (int i = 0; i < max_num_ue; ++i)
|
||||
g_start_ue_ul = next_ue_list_looped(UE_list, g_start_ue_ul);
|
||||
} else {
|
||||
/* else, just start with the next UE next time */
|
||||
g_start_ue_ul = next_ue_list_looped(UE_list, g_start_ue_ul);
|
||||
}
|
||||
/* just start with the next UE next time */
|
||||
*start_ue = next_ue_list_looped(UE_list, *start_ue);
|
||||
|
||||
return rbs[0].length + (num_contig_rb > 1 ? rbs[1].length : 0);
|
||||
}
|
||||
default_sched_ul_algo_t round_robin_ul = {
|
||||
.name = "round_robin_ul",
|
||||
.setup = rr_ul_setup,
|
||||
.unset = rr_ul_unset,
|
||||
.run = rr_ul_run,
|
||||
.data = NULL
|
||||
};
|
||||
|
||||
void ulsch_scheduler_pre_processor(module_id_t Mod_id,
|
||||
int CC_id,
|
||||
int frameP,
|
||||
frame_t frameP,
|
||||
sub_frame_t subframeP,
|
||||
int sched_frameP,
|
||||
unsigned char sched_subframeP) {
|
||||
UE_info_t *UE_info = &RC.mac[Mod_id]->UE_info;
|
||||
const int N_RB_UL = to_prb(RC.mac[Mod_id]->common_channels[CC_id].ul_Bandwidth);
|
||||
COMMON_channels_t *cc = &RC.mac[Mod_id]->common_channels[CC_id];
|
||||
frame_t sched_frameP,
|
||||
sub_frame_t sched_subframeP) {
|
||||
eNB_MAC_INST *mac = RC.mac[Mod_id];
|
||||
UE_info_t *UE_info = &mac->UE_info;
|
||||
const int N_RB_UL = to_prb(mac->common_channels[CC_id].ul_Bandwidth);
|
||||
COMMON_channels_t *cc = &mac->common_channels[CC_id];
|
||||
|
||||
UE_list_t UE_to_sched;
|
||||
UE_to_sched.head = -1;
|
||||
for (int i = 0; i < MAX_MOBILES_PER_ENB; ++i)
|
||||
UE_to_sched.next[i] = -1;
|
||||
int *cur = &UE_to_sched.head;
|
||||
|
||||
int last_UE_id = -1;
|
||||
for (int UE_id = UE_info->list.head; UE_id >= 0; UE_id = UE_info->list.next[UE_id]) {
|
||||
UE_TEMPLATE *UE_template = &UE_info->UE_template[CC_id][UE_id];
|
||||
UE_sched_ctrl_t *ue_sched_ctrl = &UE_info->UE_sched_ctrl[UE_id];
|
||||
@@ -793,13 +1116,10 @@ void ulsch_scheduler_pre_processor(module_id_t Mod_id,
|
||||
continue;
|
||||
|
||||
/* define UEs to schedule */
|
||||
if (UE_to_sched.head < 0)
|
||||
UE_to_sched.head = UE_id;
|
||||
else
|
||||
UE_to_sched.next[last_UE_id] = UE_id;
|
||||
UE_to_sched.next[UE_id] = -1;
|
||||
last_UE_id = UE_id;
|
||||
*cur = UE_id;
|
||||
cur = &UE_to_sched.next[UE_id];
|
||||
}
|
||||
*cur = -1;
|
||||
|
||||
if (UE_to_sched.head < 0)
|
||||
return;
|
||||
@@ -820,16 +1140,17 @@ void ulsch_scheduler_pre_processor(module_id_t Mod_id,
|
||||
}
|
||||
}
|
||||
|
||||
round_robin_ul(Mod_id,
|
||||
CC_id,
|
||||
frameP,
|
||||
subframeP,
|
||||
sched_frameP,
|
||||
sched_subframeP,
|
||||
&UE_to_sched,
|
||||
4, // max_num_ue
|
||||
n_contig,
|
||||
rbs);
|
||||
mac->pre_processor_ul.ul_algo.run(Mod_id,
|
||||
CC_id,
|
||||
frameP,
|
||||
subframeP,
|
||||
sched_frameP,
|
||||
sched_subframeP,
|
||||
&UE_to_sched,
|
||||
4, // max_num_ue
|
||||
n_contig,
|
||||
rbs,
|
||||
mac->pre_processor_ul.ul_algo.data);
|
||||
|
||||
// the following block is meant for validation of the pre-processor to check
|
||||
// whether all UE allocations are non-overlapping and is not necessary for
|
||||
@@ -848,7 +1169,7 @@ void ulsch_scheduler_pre_processor(module_id_t Mod_id,
|
||||
continue;
|
||||
|
||||
print = 1;
|
||||
uint8_t harq_pid = subframe2harqpid(&RC.mac[Mod_id]->common_channels[CC_id],
|
||||
uint8_t harq_pid = subframe2harqpid(&mac->common_channels[CC_id],
|
||||
sched_frameP, sched_subframeP);
|
||||
LOG_D(MAC, "%4d.%d UE%d %d RBs (index %d) at start %d, pre MCS %d %s\n",
|
||||
frameP,
|
||||
|
||||
@@ -0,0 +1,601 @@
|
||||
/*
|
||||
* 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 slicing.c
|
||||
* \brief Generic slicing helper functions and Static Slicing Implementation
|
||||
* \author Robert Schmidt
|
||||
* \date 2020
|
||||
* \email robert.schmidt@eurecom.fr
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "assertions.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
|
||||
#include "slicing.h"
|
||||
#include "slicing_internal.h"
|
||||
|
||||
#include "common/ran_context.h"
|
||||
extern RAN_CONTEXT_t RC;
|
||||
|
||||
#define RET_FAIL(ret, x...) do { LOG_E(MAC, x); return ret; } while (0)
|
||||
|
||||
int slicing_get_UE_slice_idx(slice_info_t *si, int UE_id) {
|
||||
return si->UE_assoc_slice[UE_id];
|
||||
}
|
||||
|
||||
void slicing_add_UE(slice_info_t *si, int UE_id) {
|
||||
add_ue_list(&si->s[0]->UEs, UE_id);
|
||||
si->UE_assoc_slice[UE_id] = 0;
|
||||
}
|
||||
|
||||
void _remove_UE(slice_t **s, uint8_t *assoc, int UE_id) {
|
||||
const uint8_t i = assoc[UE_id];
|
||||
DevAssert(remove_ue_list(&s[i]->UEs, UE_id));
|
||||
assoc[UE_id] = -1;
|
||||
}
|
||||
|
||||
void slicing_remove_UE(slice_info_t *si, int UE_id) {
|
||||
_remove_UE(si->s, si->UE_assoc_slice, UE_id);
|
||||
}
|
||||
|
||||
void _move_UE(slice_t **s, uint8_t *assoc, int UE_id, int to) {
|
||||
const uint8_t i = assoc[UE_id];
|
||||
const int ri = remove_ue_list(&s[i]->UEs, UE_id);
|
||||
if (!ri)
|
||||
LOG_W(MAC, "did not find UE %d in DL slice index %d\n", UE_id, i);
|
||||
add_ue_list(&s[to]->UEs, UE_id);
|
||||
assoc[UE_id] = to;
|
||||
}
|
||||
|
||||
void slicing_move_UE(slice_info_t *si, int UE_id, int idx) {
|
||||
DevAssert(idx >= -1 && idx < si->num);
|
||||
if (idx >= 0)
|
||||
_move_UE(si->s, si->UE_assoc_slice, UE_id, idx);
|
||||
}
|
||||
|
||||
int _exists_slice(uint8_t n, slice_t **s, int id) {
|
||||
for (int i = 0; i < n; ++i)
|
||||
if (s[i]->id == id)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
slice_t *_add_slice(uint8_t *n, slice_t **s) {
|
||||
s[*n] = calloc(1, sizeof(slice_t));
|
||||
if (!s[*n])
|
||||
return NULL;
|
||||
init_ue_list(&s[*n]->UEs);
|
||||
*n += 1;
|
||||
return s[*n - 1];
|
||||
}
|
||||
|
||||
slice_t *_remove_slice(uint8_t *n, slice_t **s, uint8_t *assoc, int idx) {
|
||||
if (idx >= *n)
|
||||
return NULL;
|
||||
|
||||
slice_t *sr = s[idx];
|
||||
while (sr->UEs.head >= 0)
|
||||
_move_UE(s, assoc, sr->UEs.head, 0);
|
||||
|
||||
for (int i = idx + 1; i < *n; ++i)
|
||||
s[i - 1] = s[i];
|
||||
*n -= 1;
|
||||
s[*n] = NULL;
|
||||
|
||||
for (int i = 0; i < MAX_MOBILES_PER_ENB; ++i)
|
||||
if (assoc[i] > idx)
|
||||
assoc[i] -= 1;
|
||||
|
||||
if (sr->label)
|
||||
free(sr->label);
|
||||
|
||||
return sr;
|
||||
}
|
||||
|
||||
/************************ Static Slicing Implementation ************************/
|
||||
|
||||
int addmod_static_slice_dl(slice_info_t *si,
|
||||
int id,
|
||||
char *label,
|
||||
void *algo,
|
||||
void *slice_params_dl) {
|
||||
static_slice_param_t *dl = slice_params_dl;
|
||||
if (dl && dl->posLow > dl->posHigh)
|
||||
RET_FAIL(-1, "%s(): slice id %d posLow > posHigh\n", __func__, id);
|
||||
|
||||
uint8_t rbgMap[25] = { 0 };
|
||||
int index = _exists_slice(si->num, si->s, id);
|
||||
if (index >= 0) {
|
||||
for (int s = 0; s < si->num; ++s) {
|
||||
static_slice_param_t *sd = dl && si->s[s]->id == id ? dl : si->s[s]->algo_data;
|
||||
for (int i = sd->posLow; i <= sd->posHigh; ++i) {
|
||||
if (rbgMap[i])
|
||||
RET_FAIL(-33, "%s(): overlap of slices detected at RBG %d\n", __func__, i);
|
||||
rbgMap[i] = 1;
|
||||
}
|
||||
}
|
||||
/* no problem, can allocate */
|
||||
slice_t *s = si->s[index];
|
||||
if (label) {
|
||||
if (s->label) free(s->label);
|
||||
s->label = label;
|
||||
}
|
||||
if (algo) {
|
||||
s->dl_algo.unset(&s->dl_algo.data);
|
||||
s->dl_algo = *(default_sched_dl_algo_t *) algo;
|
||||
if (!s->dl_algo.data)
|
||||
s->dl_algo.data = s->dl_algo.setup();
|
||||
}
|
||||
if (dl) {
|
||||
free(s->algo_data);
|
||||
s->algo_data = dl;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
if (!dl)
|
||||
RET_FAIL(-100, "%s(): no parameters for new slice %d, aborting\n", __func__, id);
|
||||
|
||||
if (si->num >= MAX_STATIC_SLICES)
|
||||
RET_FAIL(-2, "%s(): cannot have more than %d slices\n", __func__, MAX_STATIC_SLICES);
|
||||
for (int s = 0; s < si->num; ++s) {
|
||||
static_slice_param_t *sd = si->s[s]->algo_data;
|
||||
for (int i = sd->posLow; i <= sd->posHigh; ++i)
|
||||
rbgMap[i] = 1;
|
||||
}
|
||||
|
||||
for (int i = dl->posLow; i <= dl->posHigh; ++i)
|
||||
if (rbgMap[i])
|
||||
RET_FAIL(-3, "%s(): overlap of slices detected at RBG %d\n", __func__, i);
|
||||
|
||||
if (!algo)
|
||||
RET_FAIL(-14, "%s(): no scheduler algorithm provided\n", __func__);
|
||||
|
||||
slice_t *ns = _add_slice(&si->num, si->s);
|
||||
if (!ns)
|
||||
RET_FAIL(-4, "%s(): could not create new slice\n", __func__);
|
||||
ns->id = id;
|
||||
ns->label = label;
|
||||
ns->dl_algo = *(default_sched_dl_algo_t *) algo;
|
||||
if (!ns->dl_algo.data)
|
||||
ns->dl_algo.data = ns->dl_algo.setup();
|
||||
ns->algo_data = dl;
|
||||
|
||||
return si->num - 1;
|
||||
}
|
||||
|
||||
int addmod_static_slice_ul(slice_info_t *si,
|
||||
int id,
|
||||
char *label,
|
||||
void *algo,
|
||||
void *slice_params_ul) {
|
||||
static_slice_param_t *ul = slice_params_ul;
|
||||
/* Minimum 3RBs, because LTE stack requires this */
|
||||
if (ul && ul->posLow + 2 > ul->posHigh)
|
||||
RET_FAIL(-1, "%s(): slice id %d posLow + 2 > posHigh\n", __func__, id);
|
||||
|
||||
uint8_t rbMap[110] = { 0 };
|
||||
int index = _exists_slice(si->num, si->s, id);
|
||||
if (index >= 0) {
|
||||
for (int s = 0; s < si->num; ++s) {
|
||||
static_slice_param_t *su = ul && si->s[s]->id == id && ul ? ul : si->s[s]->algo_data;
|
||||
for (int i = su->posLow; i <= su->posHigh; ++i) {
|
||||
if (rbMap[i])
|
||||
RET_FAIL(-33, "%s(): overlap of slices detected at RBG %d\n", __func__, i);
|
||||
rbMap[i] = 1;
|
||||
}
|
||||
}
|
||||
/* no problem, can allocate */
|
||||
slice_t *s = si->s[index];
|
||||
if (algo) {
|
||||
s->ul_algo.unset(&s->ul_algo.data);
|
||||
s->ul_algo = *(default_sched_ul_algo_t *) algo;
|
||||
if (!s->ul_algo.data)
|
||||
s->ul_algo.data = s->ul_algo.setup();
|
||||
}
|
||||
if (label) {
|
||||
if (s->label) free(s->label);
|
||||
s->label = label;
|
||||
}
|
||||
if (ul) {
|
||||
free(s->algo_data);
|
||||
s->algo_data = ul;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
if (!ul)
|
||||
RET_FAIL(-100, "%s(): no parameters for new slice %d, aborting\n", __func__, id);
|
||||
|
||||
if (si->num >= MAX_STATIC_SLICES)
|
||||
RET_FAIL(-2, "%s(): cannot have more than %d slices\n", __func__, MAX_STATIC_SLICES);
|
||||
for (int s = 0; s < si->num; ++s) {
|
||||
static_slice_param_t *sd = si->s[s]->algo_data;
|
||||
for (int i = sd->posLow; i <= sd->posHigh; ++i)
|
||||
rbMap[i] = 1;
|
||||
}
|
||||
|
||||
for (int i = ul->posLow; i <= ul->posHigh; ++i)
|
||||
if (rbMap[i])
|
||||
RET_FAIL(-3, "%s(): overlap of slices detected at RBG %d\n", __func__, i);
|
||||
|
||||
if (!algo)
|
||||
RET_FAIL(-14, "%s(): no scheduler algorithm provided\n", __func__);
|
||||
|
||||
slice_t *ns = _add_slice(&si->num, si->s);
|
||||
if (!ns)
|
||||
RET_FAIL(-4, "%s(): could not create new slice\n", __func__);
|
||||
ns->id = id;
|
||||
ns->label = label;
|
||||
ns->ul_algo = *(default_sched_ul_algo_t *) algo;
|
||||
if (!ns->ul_algo.data)
|
||||
ns->ul_algo.data = ns->ul_algo.setup();
|
||||
ns->algo_data = ul;
|
||||
|
||||
return si->num - 1;
|
||||
}
|
||||
|
||||
int remove_static_slice_dl(slice_info_t *si, uint8_t slice_idx) {
|
||||
if (slice_idx == 0)
|
||||
return 0;
|
||||
slice_t *sr = _remove_slice(&si->num, si->s, si->UE_assoc_slice, slice_idx);
|
||||
if (!sr)
|
||||
return 0;
|
||||
free(sr->algo_data);
|
||||
sr->dl_algo.unset(&sr->dl_algo.data);
|
||||
free(sr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int remove_static_slice_ul(slice_info_t *si, uint8_t slice_idx) {
|
||||
if (slice_idx == 0)
|
||||
return 0;
|
||||
slice_t *sr = _remove_slice(&si->num, si->s, si->UE_assoc_slice, slice_idx);
|
||||
if (!sr)
|
||||
return 0;
|
||||
free(sr->algo_data);
|
||||
sr->ul_algo.unset(&sr->ul_algo.data);
|
||||
free(sr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void static_dl(module_id_t mod_id,
|
||||
int CC_id,
|
||||
frame_t frame,
|
||||
sub_frame_t subframe) {
|
||||
UE_info_t *UE_info = &RC.mac[mod_id]->UE_info;
|
||||
|
||||
store_dlsch_buffer(mod_id, CC_id, frame, subframe);
|
||||
|
||||
for (int UE_id = UE_info->list.head; UE_id >= 0; UE_id = UE_info->list.next[UE_id]) {
|
||||
UE_sched_ctrl_t *ue_sched_ctrl = &UE_info->UE_sched_ctrl[UE_id];
|
||||
|
||||
/* initialize per-UE scheduling information */
|
||||
ue_sched_ctrl->pre_nb_available_rbs[CC_id] = 0;
|
||||
ue_sched_ctrl->dl_pow_off[CC_id] = 2;
|
||||
memset(ue_sched_ctrl->rballoc_sub_UE[CC_id], 0, sizeof(ue_sched_ctrl->rballoc_sub_UE[CC_id]));
|
||||
ue_sched_ctrl->pre_dci_dl_pdu_idx = -1;
|
||||
}
|
||||
|
||||
const int N_RBG = to_rbg(RC.mac[mod_id]->common_channels[CC_id].mib->message.dl_Bandwidth);
|
||||
const int RBGsize = get_min_rb_unit(mod_id, CC_id);
|
||||
uint8_t *vrb_map = RC.mac[mod_id]->common_channels[CC_id].vrb_map;
|
||||
uint8_t rbgalloc_mask[N_RBG_MAX];
|
||||
for (int i = 0; i < N_RBG; i++) {
|
||||
// calculate mask: init to one + "AND" with vrb_map:
|
||||
// if any RB in vrb_map is blocked (1), the current RBG will be 0
|
||||
rbgalloc_mask[i] = 1;
|
||||
for (int j = 0; j < RBGsize; j++)
|
||||
rbgalloc_mask[i] &= !vrb_map[RBGsize * i + j];
|
||||
}
|
||||
|
||||
slice_info_t *s = RC.mac[mod_id]->pre_processor_dl.slices;
|
||||
int max_num_ue;
|
||||
switch (s->num) {
|
||||
case 1:
|
||||
max_num_ue = 4;
|
||||
break;
|
||||
case 2:
|
||||
max_num_ue = 2;
|
||||
break;
|
||||
default:
|
||||
max_num_ue = 1;
|
||||
break;
|
||||
}
|
||||
for (int i = 0; i < s->num; ++i) {
|
||||
if (s->s[i]->UEs.head < 0)
|
||||
continue;
|
||||
uint8_t rbgalloc_slice_mask[N_RBG_MAX];
|
||||
memset(rbgalloc_slice_mask, 0, sizeof(rbgalloc_slice_mask));
|
||||
static_slice_param_t *p = s->s[i]->algo_data;
|
||||
int n_rbg_sched = 0;
|
||||
for (int rbg = p->posLow; rbg <= p->posHigh && rbg <= N_RBG; ++rbg) {
|
||||
rbgalloc_slice_mask[rbg] = rbgalloc_mask[rbg];
|
||||
n_rbg_sched += rbgalloc_mask[rbg];
|
||||
}
|
||||
|
||||
s->s[i]->dl_algo.run(mod_id,
|
||||
CC_id,
|
||||
frame,
|
||||
subframe,
|
||||
&s->s[i]->UEs,
|
||||
max_num_ue, // max_num_ue
|
||||
n_rbg_sched,
|
||||
rbgalloc_slice_mask,
|
||||
s->s[i]->dl_algo.data);
|
||||
}
|
||||
|
||||
// the following block is meant for validation of the pre-processor to check
|
||||
// whether all UE allocations are non-overlapping and is not necessary for
|
||||
// scheduling functionality
|
||||
char t[26] = "_________________________";
|
||||
t[N_RBG] = 0;
|
||||
for (int i = 0; i < N_RBG; i++)
|
||||
for (int j = 0; j < RBGsize; j++)
|
||||
if (vrb_map[RBGsize*i+j] != 0)
|
||||
t[i] = 'x';
|
||||
int print = 0;
|
||||
for (int UE_id = UE_info->list.head; UE_id >= 0; UE_id = UE_info->list.next[UE_id]) {
|
||||
const UE_sched_ctrl_t *ue_sched_ctrl = &UE_info->UE_sched_ctrl[UE_id];
|
||||
|
||||
if (ue_sched_ctrl->pre_nb_available_rbs[CC_id] == 0)
|
||||
continue;
|
||||
|
||||
LOG_D(MAC,
|
||||
"%4d.%d UE%d %d RBs allocated, pre MCS %d\n",
|
||||
frame,
|
||||
subframe,
|
||||
UE_id,
|
||||
ue_sched_ctrl->pre_nb_available_rbs[CC_id],
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1);
|
||||
|
||||
print = 1;
|
||||
|
||||
for (int i = 0; i < N_RBG; i++) {
|
||||
if (!ue_sched_ctrl->rballoc_sub_UE[CC_id][i])
|
||||
continue;
|
||||
for (int j = 0; j < RBGsize; j++) {
|
||||
if (vrb_map[RBGsize*i+j] != 0) {
|
||||
LOG_I(MAC, "%4d.%d DL scheduler allocation list: %s\n", frame, subframe, t);
|
||||
LOG_E(MAC, "%4d.%d: UE %d allocated at locked RB %d/RBG %d\n", frame,
|
||||
subframe, UE_id, RBGsize * i + j, i);
|
||||
}
|
||||
vrb_map[RBGsize*i+j] = 1;
|
||||
}
|
||||
t[i] = '0' + UE_id;
|
||||
}
|
||||
}
|
||||
if (print)
|
||||
LOG_D(MAC, "%4d.%d DL scheduler allocation list: %s\n", frame, subframe, t);
|
||||
}
|
||||
|
||||
void static_ul(module_id_t mod_id,
|
||||
int CC_id,
|
||||
frame_t frame,
|
||||
sub_frame_t subframe,
|
||||
frame_t sched_frame,
|
||||
sub_frame_t sched_subframe) {
|
||||
UE_info_t *UE_info = &RC.mac[mod_id]->UE_info;
|
||||
const int N_RB_UL = to_prb(RC.mac[mod_id]->common_channels[CC_id].ul_Bandwidth);
|
||||
COMMON_channels_t *cc = &RC.mac[mod_id]->common_channels[CC_id];
|
||||
|
||||
for (int UE_id = UE_info->list.head; UE_id >= 0; UE_id = UE_info->list.next[UE_id]) {
|
||||
UE_TEMPLATE *UE_template = &UE_info->UE_template[CC_id][UE_id];
|
||||
UE_template->pre_assigned_mcs_ul = 0;
|
||||
UE_template->pre_allocated_nb_rb_ul = 0;
|
||||
UE_template->pre_allocated_rb_table_index_ul = -1;
|
||||
UE_template->pre_first_nb_rb_ul = 0;
|
||||
UE_template->pre_dci_ul_pdu_idx = -1;
|
||||
}
|
||||
|
||||
slice_info_t *s = RC.mac[mod_id]->pre_processor_ul.slices;
|
||||
int max_num_ue;
|
||||
switch (s->num) {
|
||||
case 1:
|
||||
max_num_ue = 4;
|
||||
break;
|
||||
case 2:
|
||||
max_num_ue = 2;
|
||||
break;
|
||||
default:
|
||||
max_num_ue = 1;
|
||||
break;
|
||||
}
|
||||
for (int i = 0; i < s->num; ++i) {
|
||||
if (s->s[i]->UEs.head < 0)
|
||||
continue;
|
||||
int last_rb_blocked = 1;
|
||||
int n_contig = 0;
|
||||
contig_rbs_t rbs[2]; // up to two contig RBs for PRACH in between
|
||||
static_slice_param_t *p = s->s[i]->algo_data;
|
||||
for (int rb = p->posLow; rb <= p->posHigh && rb < N_RB_UL; ++rb) {
|
||||
if (cc->vrb_map_UL[rb] == 0 && last_rb_blocked) {
|
||||
last_rb_blocked = 0;
|
||||
n_contig++;
|
||||
AssertFatal(n_contig <= 2, "cannot handle more than two contiguous RB regions\n");
|
||||
rbs[n_contig - 1].start = rb;
|
||||
}
|
||||
if (cc->vrb_map_UL[rb] == 1 && !last_rb_blocked) {
|
||||
last_rb_blocked = 1;
|
||||
rbs[n_contig - 1].length = rb - rbs[n_contig - 1].start;
|
||||
}
|
||||
}
|
||||
if (!last_rb_blocked)
|
||||
rbs[n_contig - 1].length = p->posHigh - rbs[n_contig - 1].start + 1;
|
||||
|
||||
s->s[i]->ul_algo.run(mod_id,
|
||||
CC_id,
|
||||
frame,
|
||||
subframe,
|
||||
sched_frame,
|
||||
sched_subframe,
|
||||
&s->s[i]->UEs,
|
||||
max_num_ue, // max_num_ue
|
||||
n_contig,
|
||||
rbs,
|
||||
s->s[i]->ul_algo.data);
|
||||
}
|
||||
|
||||
// the following block is meant for validation of the pre-processor to check
|
||||
// whether all UE allocations are non-overlapping and is not necessary for
|
||||
// scheduling functionality
|
||||
char t[101] = "__________________________________________________"
|
||||
"__________________________________________________";
|
||||
t[N_RB_UL] = 0;
|
||||
for (int j = 0; j < N_RB_UL; j++)
|
||||
if (cc->vrb_map_UL[j] != 0)
|
||||
t[j] = 'x';
|
||||
int print = 0;
|
||||
for (int UE_id = UE_info->list.head; UE_id >= 0; UE_id = UE_info->list.next[UE_id]) {
|
||||
UE_TEMPLATE *UE_template = &UE_info->UE_template[CC_id][UE_id];
|
||||
if (UE_template->pre_allocated_nb_rb_ul == 0)
|
||||
continue;
|
||||
|
||||
print = 1;
|
||||
uint8_t harq_pid = subframe2harqpid(&RC.mac[mod_id]->common_channels[CC_id],
|
||||
sched_frame, sched_subframe);
|
||||
LOG_D(MAC, "%4d.%d UE%d %d RBs (index %d) at start %d, pre MCS %d %s\n",
|
||||
frame,
|
||||
subframe,
|
||||
UE_id,
|
||||
UE_template->pre_allocated_nb_rb_ul,
|
||||
UE_template->pre_allocated_rb_table_index_ul,
|
||||
UE_template->pre_first_nb_rb_ul,
|
||||
UE_template->pre_assigned_mcs_ul,
|
||||
UE_info->UE_sched_ctrl[UE_id].round_UL[CC_id][harq_pid] > 0 ? "(retx)" : "");
|
||||
|
||||
for (int i = 0; i < UE_template->pre_allocated_nb_rb_ul; ++i) {
|
||||
/* only check if this is not a retransmission */
|
||||
if (UE_info->UE_sched_ctrl[UE_id].round_UL[CC_id][harq_pid] == 0
|
||||
&& cc->vrb_map_UL[UE_template->pre_first_nb_rb_ul + i] == 1) {
|
||||
|
||||
LOG_I(MAC, "%4d.%d UL scheduler allocation list: %s\n", frame, subframe, t);
|
||||
LOG_E(MAC,
|
||||
"%4d.%d: UE %d allocated at locked RB %d (is: allocated start "
|
||||
"%d/length %d)\n",
|
||||
frame, subframe, UE_id, UE_template->pre_first_nb_rb_ul + i,
|
||||
UE_template->pre_first_nb_rb_ul,
|
||||
UE_template->pre_allocated_nb_rb_ul);
|
||||
}
|
||||
cc->vrb_map_UL[UE_template->pre_first_nb_rb_ul + i] = 1;
|
||||
t[UE_template->pre_first_nb_rb_ul + i] = UE_id + '0';
|
||||
}
|
||||
}
|
||||
if (print)
|
||||
LOG_D(MAC,
|
||||
"%4d.%d UL scheduler allocation list: %s\n",
|
||||
sched_frame,
|
||||
sched_subframe,
|
||||
t);
|
||||
}
|
||||
|
||||
void static_destroy(slice_info_t **si) {
|
||||
const int n = (*si)->num;
|
||||
(*si)->num = 0;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
slice_t *s = (*si)->s[i];
|
||||
if (s->label)
|
||||
free(s->label);
|
||||
free(s->algo_data);
|
||||
free(s);
|
||||
}
|
||||
free((*si)->s);
|
||||
free(*si);
|
||||
}
|
||||
|
||||
pp_impl_param_t static_dl_init(module_id_t mod_id, int CC_id) {
|
||||
slice_info_t *si = calloc(1, sizeof(slice_info_t));
|
||||
DevAssert(si);
|
||||
|
||||
si->num = 0;
|
||||
si->s = calloc(MAX_STATIC_SLICES, sizeof(slice_t));
|
||||
DevAssert(si->s);
|
||||
for (int i = 0; i < MAX_MOBILES_PER_ENB; ++i)
|
||||
si->UE_assoc_slice[i] = -1;
|
||||
|
||||
/* insert default slice, all resources */
|
||||
static_slice_param_t *dlp = malloc(sizeof(static_slice_param_t));
|
||||
dlp->posLow = 0;
|
||||
dlp->posHigh = to_rbg(RC.mac[mod_id]->common_channels[CC_id].mib->message.dl_Bandwidth) - 1;
|
||||
default_sched_dl_algo_t *algo = &RC.mac[mod_id]->pre_processor_dl.dl_algo;
|
||||
algo->data = NULL;
|
||||
DevAssert(0 == addmod_static_slice_dl(si, 0, strdup("default"), algo, dlp));
|
||||
const UE_list_t *UE_list = &RC.mac[mod_id]->UE_info.list;
|
||||
for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id])
|
||||
slicing_add_UE(si, UE_id);
|
||||
|
||||
pp_impl_param_t sttc;
|
||||
sttc.algorithm = STATIC_SLICING;
|
||||
sttc.add_UE = slicing_add_UE;
|
||||
sttc.remove_UE = slicing_remove_UE;
|
||||
sttc.move_UE = slicing_move_UE;
|
||||
sttc.addmod_slice = addmod_static_slice_dl;
|
||||
sttc.remove_slice = remove_static_slice_dl;
|
||||
sttc.dl = static_dl;
|
||||
// current DL algo becomes default scheduler
|
||||
sttc.dl_algo = *algo;
|
||||
sttc.destroy = static_destroy;
|
||||
sttc.slices = si;
|
||||
|
||||
return sttc;
|
||||
}
|
||||
|
||||
pp_impl_param_t static_ul_init(module_id_t mod_id, int CC_id) {
|
||||
slice_info_t *si = calloc(1, sizeof(slice_info_t));
|
||||
DevAssert(si);
|
||||
|
||||
si->num = 0;
|
||||
si->s = calloc(MAX_STATIC_SLICES, sizeof(slice_t));
|
||||
DevAssert(si->s);
|
||||
for (int i = 0; i < MAX_MOBILES_PER_ENB; ++i)
|
||||
si->UE_assoc_slice[i] = -1;
|
||||
|
||||
/* insert default slice, all resources */
|
||||
static_slice_param_t *ulp = malloc(sizeof(static_slice_param_t));
|
||||
ulp->posLow = 0;
|
||||
ulp->posHigh = to_prb(RC.mac[mod_id]->common_channels[CC_id].ul_Bandwidth) - 1;
|
||||
default_sched_ul_algo_t *algo = &RC.mac[mod_id]->pre_processor_ul.ul_algo;
|
||||
algo->data = NULL;
|
||||
DevAssert(0 == addmod_static_slice_ul(si, 0, strdup("default"), algo, ulp));
|
||||
const UE_list_t *UE_list = &RC.mac[mod_id]->UE_info.list;
|
||||
for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id])
|
||||
slicing_add_UE(si, UE_id);
|
||||
|
||||
pp_impl_param_t sttc;
|
||||
sttc.algorithm = STATIC_SLICING;
|
||||
sttc.add_UE = slicing_add_UE;
|
||||
sttc.remove_UE = slicing_remove_UE;
|
||||
sttc.move_UE = slicing_move_UE;
|
||||
sttc.addmod_slice = addmod_static_slice_ul;
|
||||
sttc.remove_slice = remove_static_slice_ul;
|
||||
sttc.ul = static_ul;
|
||||
// current DL algo becomes default scheduler
|
||||
sttc.ul_algo = *algo;
|
||||
sttc.destroy = static_destroy;
|
||||
sttc.slices = si;
|
||||
|
||||
return sttc;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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 slicing.h
|
||||
* \brief General slice definition and helper parameters
|
||||
* \author Robert Schmidt
|
||||
* \date 2020
|
||||
* \email robert.schmidt@eurecom.fr
|
||||
*/
|
||||
|
||||
#ifndef __SLICING_H__
|
||||
#define __SLICING_H__
|
||||
|
||||
#include "openair2/LAYER2/MAC/mac.h"
|
||||
|
||||
typedef struct slice_s {
|
||||
/// Arbitrary ID
|
||||
slice_id_t id;
|
||||
/// Arbitrary label
|
||||
char *label;
|
||||
|
||||
union {
|
||||
default_sched_dl_algo_t dl_algo;
|
||||
default_sched_ul_algo_t ul_algo;
|
||||
};
|
||||
|
||||
/// A specific algorithm's implementation parameters
|
||||
void *algo_data;
|
||||
/// Internal data that might be kept alongside a slice's params
|
||||
void *int_data;
|
||||
|
||||
// list of users in this slice
|
||||
UE_list_t UEs;
|
||||
} slice_t;
|
||||
|
||||
typedef struct slice_info_s {
|
||||
uint8_t num;
|
||||
slice_t **s;
|
||||
uint8_t UE_assoc_slice[MAX_MOBILES_PER_ENB];
|
||||
} slice_info_t;
|
||||
|
||||
int slicing_get_UE_slice_idx(slice_info_t *si, int UE_id);
|
||||
|
||||
#define STATIC_SLICING 10
|
||||
/* only four static slices for UL, DL resp. (not enough DCIs) */
|
||||
#define MAX_STATIC_SLICES 4
|
||||
typedef struct {
|
||||
uint16_t posLow;
|
||||
uint16_t posHigh;
|
||||
} static_slice_param_t;
|
||||
pp_impl_param_t static_dl_init(module_id_t mod_id, int CC_id);
|
||||
pp_impl_param_t static_ul_init(module_id_t mod_id, int CC_id);
|
||||
|
||||
|
||||
#endif /* __SLICING_H__ */
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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 slicing_internal.h
|
||||
* \brief Internal slice helper functions
|
||||
* \author Robert Schmidt
|
||||
* \date 2020
|
||||
* \email robert.schmidt@eurecom.fr
|
||||
*/
|
||||
|
||||
#ifndef __SLICING_INTERNAL_H__
|
||||
#define __SLICING_INTERNAL_H__
|
||||
|
||||
#include "slicing.h"
|
||||
|
||||
void slicing_add_UE(slice_info_t *si, int UE_id);
|
||||
|
||||
void _remove_UE(slice_t **s, uint8_t *assoc, int UE_id);
|
||||
void slicing_remove_UE(slice_info_t *si, int UE_id);
|
||||
|
||||
void _move_UE(slice_t **s, uint8_t *assoc, int UE_id, int to);
|
||||
void slicing_move_UE(slice_info_t *si, int UE_id, int idx);
|
||||
|
||||
slice_t *_add_slice(uint8_t *n, slice_t **s);
|
||||
slice_t *_remove_slice(uint8_t *n, slice_t **s, uint8_t *assoc, int idx);
|
||||
|
||||
#endif /* __SLICING_INTERNAL_H__ */
|
||||
@@ -251,9 +251,8 @@ typedef struct {
|
||||
uint8_t short_messages; //8 bits
|
||||
uint8_t tb_scaling; //2 bits
|
||||
uint8_t pucch_resource_indicator; //3 bits
|
||||
uint8_t dmrs_sequence_initialization; //1 bit
|
||||
uint8_t system_info_indicator; //1 bit
|
||||
|
||||
uint8_t ulsch_indicator;
|
||||
uint8_t slot_format_indicator_count;
|
||||
uint8_t *slot_format_indicators;
|
||||
|
||||
@@ -290,6 +289,7 @@ typedef struct {
|
||||
dci_field_t cloded_loop_indicator; //variable
|
||||
dci_field_t ul_sul_indicator; //variable
|
||||
dci_field_t antenna_ports; //variable
|
||||
dci_field_t dmrs_sequence_initialization;
|
||||
dci_field_t reserved; //1_0/C-RNTI:10 bits, 1_0/P-RNTI: 6 bits, 1_0/SI-&RA-RNTI: 16 bits
|
||||
|
||||
} dci_pdu_rel15_t;
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
*/
|
||||
|
||||
#include "LAYER2/NR_MAC_gNB/mac_proto.h"
|
||||
#include <limits.h>
|
||||
|
||||
const uint8_t nr_slots_per_frame[5] = {10, 20, 40, 80, 160};
|
||||
|
||||
@@ -1879,7 +1880,8 @@ uint8_t get_K_ptrs(uint16_t nrb0, uint16_t nrb1, uint16_t N_RB) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint16_t nr_dci_size(NR_CellGroupConfig_t *secondaryCellGroup,
|
||||
uint16_t nr_dci_size(NR_ServingCellConfigCommon_t *scc,
|
||||
NR_CellGroupConfig_t *secondaryCellGroup,
|
||||
dci_pdu_rel15_t *dci_pdu,
|
||||
nr_dci_format_t format,
|
||||
nr_rnti_type_t rnti_type,
|
||||
@@ -1887,9 +1889,15 @@ uint16_t nr_dci_size(NR_CellGroupConfig_t *secondaryCellGroup,
|
||||
int bwp_id) {
|
||||
|
||||
uint16_t size = 0;
|
||||
uint16_t numRBG = 0;
|
||||
long rbg_size_config;
|
||||
int num_entries = 0;
|
||||
int pusch_antenna_ports = 1; // TODO hardcoded number of antenna ports for pusch
|
||||
NR_BWP_Downlink_t *bwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[bwp_id-1];
|
||||
NR_BWP_Uplink_t *ubwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_id-1];
|
||||
NR_PDSCH_Config_t *pdsch_config = bwp->bwp_Dedicated->pdsch_Config->choice.setup;
|
||||
NR_PUSCH_Config_t *pusch_Config = ubwp->bwp_Dedicated->pusch_Config->choice.setup;
|
||||
NR_SRS_Config_t *srs_config = ubwp->bwp_Dedicated->srs_Config->choice.setup;
|
||||
|
||||
switch(format) {
|
||||
/*Only sizes for 0_0 and 1_0 are correct at the moment*/
|
||||
@@ -1897,30 +1905,199 @@ uint16_t nr_dci_size(NR_CellGroupConfig_t *secondaryCellGroup,
|
||||
/// fixed: Format identifier 1, Hop flag 1, MCS 5, NDI 1, RV 2, HARQ PID 4, PUSCH TPC 2 Time Domain assgnmt 4 --20
|
||||
size += 20;
|
||||
size += (uint8_t)ceil( log2( (N_RB*(N_RB+1))>>1 ) ); // Freq domain assignment -- hopping scenario to be updated
|
||||
size += nr_dci_size(secondaryCellGroup,dci_pdu,NR_DL_DCI_FORMAT_1_0, rnti_type, N_RB, bwp_id) - size; // Padding to match 1_0 size
|
||||
size += nr_dci_size(scc,secondaryCellGroup,dci_pdu,NR_DL_DCI_FORMAT_1_0, rnti_type, N_RB, bwp_id) - size; // Padding to match 1_0 size
|
||||
// UL/SUL indicator assumed to be 0
|
||||
break;
|
||||
|
||||
case NR_UL_DCI_FORMAT_0_1:
|
||||
/// fixed: Format identifier 1, MCS 5, NDI 1, RV 2, HARQ PID 4, PUSCH TPC 2, SRS request 2 --17
|
||||
size += 17;
|
||||
/// fixed: Format identifier 1, MCS 5, NDI 1, RV 2, HARQ PID 4, PUSCH TPC 2, ULSCH indicator 1 --16
|
||||
size += 16;
|
||||
// Carrier indicator
|
||||
if (secondaryCellGroup->spCellConfig->spCellConfigDedicated->crossCarrierSchedulingConfig != NULL) {
|
||||
dci_pdu->carrier_indicator.nbits=3;
|
||||
size += dci_pdu->carrier_indicator.nbits;
|
||||
}
|
||||
// UL/SUL indicator
|
||||
if (secondaryCellGroup->spCellConfig->spCellConfigDedicated->supplementaryUplink != NULL) {
|
||||
dci_pdu->carrier_indicator.nbits=1;
|
||||
size += dci_pdu->ul_sul_indicator.nbits;
|
||||
}
|
||||
// BWP Indicator
|
||||
uint8_t n_ul_bwp = secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count;
|
||||
if (n_ul_bwp < 2)
|
||||
dci_pdu->bwp_indicator.nbits = n_ul_bwp;
|
||||
else
|
||||
dci_pdu->bwp_indicator.nbits = 2;
|
||||
size += dci_pdu->bwp_indicator.nbits;
|
||||
// Freq domain assignment
|
||||
if (secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->pusch_Config->choice.setup->rbg_Size != NULL)
|
||||
rbg_size_config = 1;
|
||||
else
|
||||
rbg_size_config = 0;
|
||||
numRBG = getNRBG(NRRIV2BW(ubwp->bwp_Common->genericParameters.locationAndBandwidth,275),
|
||||
NRRIV2PRBOFFSET(ubwp->bwp_Common->genericParameters.locationAndBandwidth,275),
|
||||
rbg_size_config);
|
||||
if (pusch_Config->resourceAllocation == 0)
|
||||
dci_pdu->frequency_domain_assignment.nbits = numRBG;
|
||||
else if (pusch_Config->resourceAllocation == 1)
|
||||
dci_pdu->frequency_domain_assignment.nbits = (int)ceil( log2( (N_RB*(N_RB+1))>>1 ) );
|
||||
else
|
||||
dci_pdu->frequency_domain_assignment.nbits = ((int)ceil( log2( (N_RB*(N_RB+1))>>1 ) )>numRBG) ? (int)ceil( log2( (N_RB*(N_RB+1))>>1 ) )+1 : numRBG+1;
|
||||
size += dci_pdu->frequency_domain_assignment.nbits;
|
||||
// Time domain assignment
|
||||
// VRB to PRB mapping
|
||||
if (pusch_Config->pusch_TimeDomainAllocationList==NULL) {
|
||||
if (ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList==NULL)
|
||||
num_entries = 16; // num of entries in default table
|
||||
else
|
||||
num_entries = ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.count;
|
||||
}
|
||||
else
|
||||
num_entries = pusch_Config->pusch_TimeDomainAllocationList->choice.setup->list.count;
|
||||
dci_pdu->time_domain_assignment.nbits = (int)ceil(log2(num_entries));
|
||||
size += dci_pdu->time_domain_assignment.nbits;
|
||||
// Frequency Hopping flag
|
||||
if ((pusch_Config->frequencyHopping!=NULL) && (pusch_Config->resourceAllocation != NR_PUSCH_Config__resourceAllocation_resourceAllocationType0)) {
|
||||
dci_pdu->frequency_hopping_flag.nbits = 1;
|
||||
size += 1;
|
||||
}
|
||||
// 1st DAI
|
||||
if (secondaryCellGroup->physicalCellGroupConfig->pdsch_HARQ_ACK_Codebook==NR_PhysicalCellGroupConfig__pdsch_HARQ_ACK_Codebook_dynamic)
|
||||
dci_pdu->dai[0].nbits = 2;
|
||||
else
|
||||
dci_pdu->dai[0].nbits = 1;
|
||||
size += dci_pdu->dai[0].nbits;
|
||||
// 2nd DAI
|
||||
if (secondaryCellGroup->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup->codeBlockGroupTransmission != NULL) { //TODO not sure about that
|
||||
dci_pdu->dai[1].nbits = 2;
|
||||
size += dci_pdu->dai[1].nbits;
|
||||
}
|
||||
// SRS resource indicator
|
||||
if (pusch_Config->txConfig != NULL){
|
||||
int count=0;
|
||||
if (*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook){
|
||||
for (int i=0; i<srs_config->srs_ResourceSetToAddModList->list.count; i++) {
|
||||
if (srs_config->srs_ResourceSetToAddModList->list.array[i]->usage == NR_SRS_ResourceSet__usage_codebook)
|
||||
count++;
|
||||
}
|
||||
if (count>1) {
|
||||
dci_pdu->srs_resource_indicator.nbits = 1;
|
||||
size += dci_pdu->srs_resource_indicator.nbits;
|
||||
}
|
||||
}
|
||||
else {
|
||||
int lmin,Lmax = 0;
|
||||
int lsum = 0;
|
||||
if ( secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig != NULL) {
|
||||
if ( secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers != NULL)
|
||||
Lmax = *secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers;
|
||||
else
|
||||
AssertFatal(1==0,"MIMO on PUSCH not supported, maxMIMO_Layers needs to be set to 1\n");
|
||||
}
|
||||
else
|
||||
AssertFatal(1==0,"MIMO on PUSCH not supported, maxMIMO_Layers needs to be set to 1\n");
|
||||
for (int i=0; i<srs_config->srs_ResourceSetToAddModList->list.count; i++) {
|
||||
if (srs_config->srs_ResourceSetToAddModList->list.array[i]->usage == NR_SRS_ResourceSet__usage_nonCodebook)
|
||||
count++;
|
||||
if (count < Lmax) lmin = count;
|
||||
else lmin = Lmax;
|
||||
for (int k=1;k<=lmin;k++) {
|
||||
lsum += binomial(count,k);
|
||||
}
|
||||
}
|
||||
dci_pdu->srs_resource_indicator.nbits = (int)ceil(log2(lsum));
|
||||
size += dci_pdu->srs_resource_indicator.nbits;
|
||||
}
|
||||
}
|
||||
// Precoding info and number of layers
|
||||
long transformPrecoder;
|
||||
if (pusch_Config->transformPrecoder == NULL){
|
||||
// if transform precoder is null, apply the values from msg3
|
||||
if(scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder == NULL)
|
||||
transformPrecoder = 1;
|
||||
else
|
||||
transformPrecoder = 0;
|
||||
}
|
||||
else
|
||||
transformPrecoder = *pusch_Config->transformPrecoder;
|
||||
if (pusch_Config->txConfig != NULL){
|
||||
if (*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook){
|
||||
if (pusch_antenna_ports > 1) {
|
||||
if (pusch_antenna_ports == 4) {
|
||||
if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) && (*pusch_Config->maxRank>1))
|
||||
dci_pdu->precoding_information.nbits = 6-(*pusch_Config->codebookSubset);
|
||||
else {
|
||||
if(*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent)
|
||||
dci_pdu->precoding_information.nbits = 2;
|
||||
else
|
||||
dci_pdu->precoding_information.nbits = 5-(*pusch_Config->codebookSubset);
|
||||
}
|
||||
}
|
||||
else {
|
||||
AssertFatal(pusch_antenna_ports==2,"Not valid number of antenna ports");
|
||||
if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) && (*pusch_Config->maxRank==2))
|
||||
dci_pdu->precoding_information.nbits = 4-(*pusch_Config->codebookSubset);
|
||||
else
|
||||
dci_pdu->precoding_information.nbits = 3-(*pusch_Config->codebookSubset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
size += dci_pdu->precoding_information.nbits;
|
||||
// Antenna ports
|
||||
NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig = NULL;
|
||||
int xa=0;
|
||||
int xb=0;
|
||||
if(pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA != NULL){
|
||||
NR_DMRS_UplinkConfig = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup;
|
||||
xa = ul_ant_bits(NR_DMRS_UplinkConfig,transformPrecoder);
|
||||
}
|
||||
if(pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB != NULL){
|
||||
NR_DMRS_UplinkConfig = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup;
|
||||
xb = ul_ant_bits(NR_DMRS_UplinkConfig,transformPrecoder);
|
||||
}
|
||||
if (xa>xb)
|
||||
dci_pdu->antenna_ports.nbits = xa;
|
||||
else
|
||||
dci_pdu->antenna_ports.nbits = xb;
|
||||
size += dci_pdu->antenna_ports.nbits;
|
||||
// SRS request
|
||||
if (secondaryCellGroup->spCellConfig->spCellConfigDedicated->supplementaryUplink==NULL)
|
||||
dci_pdu->srs_request.nbits = 2;
|
||||
else
|
||||
dci_pdu->srs_request.nbits = 3;
|
||||
size += dci_pdu->srs_request.nbits;
|
||||
// CSI request
|
||||
if (secondaryCellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig != NULL) {
|
||||
if (secondaryCellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup->reportTriggerSize != NULL) {
|
||||
dci_pdu->csi_request.nbits = *secondaryCellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup->reportTriggerSize;
|
||||
size += dci_pdu->csi_request.nbits;
|
||||
}
|
||||
}
|
||||
// CBGTI
|
||||
if (secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig->choice.setup->codeBlockGroupTransmission != NULL) {
|
||||
int num = secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig->choice.setup->codeBlockGroupTransmission->choice.setup->maxCodeBlockGroupsPerTransportBlock;
|
||||
dci_pdu->cbgti.nbits = 2 + (num<<1);
|
||||
size += dci_pdu->cbgti.nbits;
|
||||
}
|
||||
// PTRS - DMRS association
|
||||
if ( (NR_DMRS_UplinkConfig->phaseTrackingRS == NULL && transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) ||
|
||||
transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled || (*pusch_Config->maxRank==1) )
|
||||
dci_pdu->ptrs_dmrs_association.nbits = 0;
|
||||
else
|
||||
dci_pdu->ptrs_dmrs_association.nbits = 2;
|
||||
size += dci_pdu->ptrs_dmrs_association.nbits;
|
||||
// beta offset indicator
|
||||
if (pusch_Config->uci_OnPUSCH!=NULL){
|
||||
if (pusch_Config->uci_OnPUSCH->choice.setup->betaOffsets->present == NR_UCI_OnPUSCH__betaOffsets_PR_dynamic) {
|
||||
dci_pdu->beta_offset_indicator.nbits = 2;
|
||||
size += dci_pdu->beta_offset_indicator.nbits;
|
||||
}
|
||||
}
|
||||
// DMRS sequence init
|
||||
if (transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) {
|
||||
dci_pdu->dmrs_sequence_initialization.nbits = 1;
|
||||
size += dci_pdu->dmrs_sequence_initialization.nbits;
|
||||
}
|
||||
break;
|
||||
|
||||
case NR_DL_DCI_FORMAT_1_0:
|
||||
@@ -1946,10 +2123,10 @@ uint16_t nr_dci_size(NR_CellGroupConfig_t *secondaryCellGroup,
|
||||
dci_pdu->bwp_indicator.nbits = 2;
|
||||
size += dci_pdu->bwp_indicator.nbits;
|
||||
// Freq domain assignment
|
||||
long rbg_size_config = secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->rbg_Size;
|
||||
uint16_t numRBG = getNRBG(NRRIV2BW(bwp->bwp_Common->genericParameters.locationAndBandwidth,275),
|
||||
NRRIV2PRBOFFSET(bwp->bwp_Common->genericParameters.locationAndBandwidth,275),
|
||||
rbg_size_config);
|
||||
rbg_size_config = secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->rbg_Size;
|
||||
numRBG = getNRBG(NRRIV2BW(bwp->bwp_Common->genericParameters.locationAndBandwidth,275),
|
||||
NRRIV2PRBOFFSET(bwp->bwp_Common->genericParameters.locationAndBandwidth,275),
|
||||
rbg_size_config);
|
||||
if (pdsch_config->resourceAllocation == 0)
|
||||
dci_pdu->frequency_domain_assignment.nbits = numRBG;
|
||||
else if (pdsch_config->resourceAllocation == 1)
|
||||
@@ -1958,7 +2135,6 @@ uint16_t nr_dci_size(NR_CellGroupConfig_t *secondaryCellGroup,
|
||||
dci_pdu->frequency_domain_assignment.nbits = ((int)ceil( log2( (N_RB*(N_RB+1))>>1 ) )>numRBG) ? (int)ceil( log2( (N_RB*(N_RB+1))>>1 ) )+1 : numRBG+1;
|
||||
size += dci_pdu->frequency_domain_assignment.nbits;
|
||||
// Time domain assignment (see table 5.1.2.1.1-1 in 38.214
|
||||
int num_entries;
|
||||
if (pdsch_config->pdsch_TimeDomainAllocationList==NULL) {
|
||||
if (bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList==NULL)
|
||||
num_entries = 16; // num of entries in default table
|
||||
@@ -2068,6 +2244,27 @@ uint16_t nr_dci_size(NR_CellGroupConfig_t *secondaryCellGroup,
|
||||
return size;
|
||||
}
|
||||
|
||||
int ul_ant_bits(NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig, long transformPrecoder) {
|
||||
|
||||
uint8_t type,maxl;
|
||||
if(NR_DMRS_UplinkConfig->dmrs_Type == NULL)
|
||||
type = 1;
|
||||
else
|
||||
type = 2;
|
||||
if(NR_DMRS_UplinkConfig->maxLength == NULL)
|
||||
maxl = 1;
|
||||
else
|
||||
maxl = 2;
|
||||
if (transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled)
|
||||
return( maxl+type+1);
|
||||
else {
|
||||
if (type==1)
|
||||
return (maxl<<1);
|
||||
else
|
||||
AssertFatal(1==0,"DMRS type not valid for this choice");
|
||||
}
|
||||
}
|
||||
|
||||
int tdd_period_to_num[8] = {500,625,1000,1250,2000,2500,5000,10000};
|
||||
|
||||
int is_nr_DL_slot(NR_ServingCellConfigCommon_t *scc,slot_t slot) {
|
||||
@@ -2208,3 +2405,20 @@ int16_t fill_dmrs_mask(NR_PDSCH_Config_t *pdsch_Config,int dmrs_TypeA_Position,i
|
||||
AssertFatal(1==0,"Shouldn't get here\n");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
|
||||
int binomial(int n, int k) {
|
||||
int c = 1, i;
|
||||
|
||||
if (k > n-k)
|
||||
k = n-k;
|
||||
|
||||
for (i = 1; i <= k; i++, n--) {
|
||||
if (c/i > UINT_MAX/n) // return 0 on overflow
|
||||
return 0;
|
||||
|
||||
c = c / i * n + c % i * n / i;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,8 @@ int is_nr_DL_slot(NR_ServingCellConfigCommon_t *scc,slot_t slotP);
|
||||
|
||||
int is_nr_UL_slot(NR_ServingCellConfigCommon_t *scc,slot_t slotP);
|
||||
|
||||
uint16_t nr_dci_size(NR_CellGroupConfig_t *secondaryCellGroup,
|
||||
uint16_t nr_dci_size(NR_ServingCellConfigCommon_t *scc,
|
||||
NR_CellGroupConfig_t *secondaryCellGroup,
|
||||
dci_pdu_rel15_t *dci_pdu,
|
||||
nr_dci_format_t format,
|
||||
nr_rnti_type_t rnti_type,
|
||||
@@ -103,6 +104,8 @@ uint8_t compute_nr_root_seq(NR_RACH_ConfigCommon_t *rach_config,
|
||||
uint8_t nb_preambles,
|
||||
uint8_t unpaired);
|
||||
|
||||
int ul_ant_bits(NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig,long transformPrecoder);
|
||||
|
||||
int get_format0(uint8_t index, uint8_t unpaired);
|
||||
|
||||
uint16_t get_NCS(uint8_t index, uint16_t format, uint8_t restricted_set_config);
|
||||
|
||||
@@ -223,7 +223,7 @@ void ue_dci_configuration(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_request_t *dl
|
||||
rel15->BWPSize = NRRIV2BW(initialDownlinkBWP->genericParameters.locationAndBandwidth, 275);
|
||||
rel15->BWPStart = NRRIV2PRBOFFSET(bwp_Common->genericParameters.locationAndBandwidth, 275); // NRRIV2PRBOFFSET(initialDownlinkBWP->genericParameters.locationAndBandwidth, 275);
|
||||
rel15->SubcarrierSpacing = initialDownlinkBWP->genericParameters.subcarrierSpacing;
|
||||
rel15->dci_length = nr_dci_size(mac->scg,def_dci_pdu_rel15,rel15->dci_format,NR_RNTI_C,rel15->BWPSize,bwp_id);
|
||||
rel15->dci_length = nr_dci_size(scc,mac->scg,def_dci_pdu_rel15,rel15->dci_format,NR_RNTI_C,rel15->BWPSize,bwp_id);
|
||||
for (int i = 0; i < sps; i++)
|
||||
if ((monitoringSymbolsWithinSlot >> (sps - 1 - i)) & 1) {
|
||||
rel15->coreset.StartSymbolIndex = i;
|
||||
@@ -243,7 +243,7 @@ void ue_dci_configuration(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_request_t *dl
|
||||
rel15->BWPSize = NRRIV2BW(bwp_Common->genericParameters.locationAndBandwidth, 275);
|
||||
rel15->BWPStart = NRRIV2PRBOFFSET(bwp_Common->genericParameters.locationAndBandwidth, 275);
|
||||
rel15->SubcarrierSpacing = bwp_Common->genericParameters.subcarrierSpacing;
|
||||
rel15->dci_length = nr_dci_size(mac->scg,def_dci_pdu_rel15,rel15->dci_format,NR_RNTI_C,rel15->BWPSize,bwp_id);
|
||||
rel15->dci_length = nr_dci_size(scc,mac->scg,def_dci_pdu_rel15,rel15->dci_format,NR_RNTI_C,rel15->BWPSize,bwp_id);
|
||||
// get UE-specific search space
|
||||
for (ss_id = 0; ss_id < FAPI_NR_MAX_SS_PER_CORESET && mac->SSpace[0][0][ss_id] != NULL; ss_id++){
|
||||
uss = mac->SSpace[0][0][ss_id];
|
||||
|
||||
@@ -773,8 +773,8 @@ NR_UE_L2_STATE_t nr_ue_scheduler(nr_downlink_indication_t *dl_info, nr_uplink_in
|
||||
uint16_t rnti = 0x1234;
|
||||
uint32_t rb_size = 50;
|
||||
uint32_t rb_start = 0;
|
||||
uint8_t nr_of_symbols = 12;
|
||||
uint8_t start_symbol_index = 2;
|
||||
uint8_t nr_of_symbols = 11;
|
||||
uint8_t start_symbol_index = 0;
|
||||
uint8_t nrOfLayers = 1;
|
||||
uint8_t mcs_index = 9;
|
||||
uint8_t mcs_table = 0;
|
||||
@@ -2235,9 +2235,14 @@ int8_t nr_ue_process_dci_time_dom_resource_assignment(NR_UE_MAC_INST_t *mac,
|
||||
pdsch_TimeDomainAllocationList = mac->DLbwp[0]->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList;
|
||||
if (pdsch_TimeDomainAllocationList) {
|
||||
|
||||
AssertFatal(pdsch_TimeDomainAllocationList->list.count > time_domain_ind,
|
||||
"time_domain_ind %d >= pdsch->TimeDomainAllocationList->list.count %d\n",
|
||||
time_domain_ind,pdsch_TimeDomainAllocationList->list.count);
|
||||
if (time_domain_ind >= pdsch_TimeDomainAllocationList->list.count) {
|
||||
LOG_E(MAC, "time_domain_ind %d >= pdsch->TimeDomainAllocationList->list.count %d\n",
|
||||
time_domain_ind, pdsch_TimeDomainAllocationList->list.count);
|
||||
dlsch_config_pdu->start_symbol = 0;
|
||||
dlsch_config_pdu->number_symbols = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int startSymbolAndLength = pdsch_TimeDomainAllocationList->list.array[time_domain_ind]->startSymbolAndLength;
|
||||
int S,L;
|
||||
SLIV2SL(startSymbolAndLength,&S,&L);
|
||||
@@ -2345,10 +2350,8 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, dc
|
||||
/* FREQ_DOM_RESOURCE_ASSIGNMENT_UL */
|
||||
nr_ue_process_dci_freq_dom_resource_assignment(pusch_config_pdu_0_0,NULL,n_RB_ULBWP,0,dci->frequency_domain_assignment.val);
|
||||
/* TIME_DOM_RESOURCE_ASSIGNMENT */
|
||||
nr_ue_process_dci_time_dom_resource_assignment(mac,
|
||||
pusch_config_pdu_0_0,NULL,
|
||||
dci->time_domain_assignment.val);
|
||||
|
||||
if (nr_ue_process_dci_time_dom_resource_assignment(mac,pusch_config_pdu_0_0,NULL,dci->time_domain_assignment.val) < 0)
|
||||
break;
|
||||
/* FREQ_HOPPING_FLAG */
|
||||
if ((mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.resource_allocation != 0) &&
|
||||
(mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.frequency_hopping !=0))
|
||||
@@ -2421,8 +2424,8 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, dc
|
||||
/* FREQ_DOM_RESOURCE_ASSIGNMENT_UL */
|
||||
nr_ue_process_dci_freq_dom_resource_assignment(pusch_config_pdu_0_1,NULL,n_RB_ULBWP,0,dci->frequency_domain_assignment.val);
|
||||
/* TIME_DOM_RESOURCE_ASSIGNMENT */
|
||||
nr_ue_process_dci_time_dom_resource_assignment(mac,pusch_config_pdu_0_1,NULL,
|
||||
dci->time_domain_assignment.val);
|
||||
if (nr_ue_process_dci_time_dom_resource_assignment(mac,pusch_config_pdu_0_1,NULL,dci->time_domain_assignment.val) < 0)
|
||||
break;
|
||||
/* FREQ_HOPPING_FLAG */
|
||||
if ((mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.resource_allocation != 0) &&
|
||||
(mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.frequency_hopping !=0))
|
||||
@@ -2752,9 +2755,8 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, dc
|
||||
/* FREQ_DOM_RESOURCE_ASSIGNMENT_DL */
|
||||
nr_ue_process_dci_freq_dom_resource_assignment(NULL,dlsch_config_pdu_1_0,0,n_RB_DLBWP,dci->frequency_domain_assignment.val);
|
||||
/* TIME_DOM_RESOURCE_ASSIGNMENT */
|
||||
nr_ue_process_dci_time_dom_resource_assignment(mac,NULL,dlsch_config_pdu_1_0,
|
||||
dci->time_domain_assignment.val);
|
||||
|
||||
if (nr_ue_process_dci_time_dom_resource_assignment(mac,NULL,dlsch_config_pdu_1_0,dci->time_domain_assignment.val) < 0)
|
||||
break;
|
||||
/* dmrs symbol positions*/
|
||||
dlsch_config_pdu_1_0->dlDmrsSymbPos = fill_dmrs_mask(pdsch_config,
|
||||
mac->scc->dmrs_TypeA_Position,
|
||||
@@ -2872,8 +2874,8 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, dc
|
||||
/* FREQ_DOM_RESOURCE_ASSIGNMENT_DL */
|
||||
nr_ue_process_dci_freq_dom_resource_assignment(NULL,dlsch_config_pdu_1_1,0,n_RB_DLBWP,dci->frequency_domain_assignment.val);
|
||||
/* TIME_DOM_RESOURCE_ASSIGNMENT */
|
||||
nr_ue_process_dci_time_dom_resource_assignment(mac,NULL,dlsch_config_pdu_1_1,
|
||||
dci->time_domain_assignment.val);
|
||||
if (nr_ue_process_dci_time_dom_resource_assignment(mac,NULL,dlsch_config_pdu_1_1,dci->time_domain_assignment.val) < 0)
|
||||
break;
|
||||
/* dmrs symbol positions*/
|
||||
dlsch_config_pdu_1_1->dlDmrsSymbPos = fill_dmrs_mask(pdsch_config,
|
||||
mac->scc->dmrs_TypeA_Position,
|
||||
@@ -3142,7 +3144,7 @@ void nr_extract_dci_info(NR_UE_MAC_INST_t *mac,
|
||||
pos+=4;
|
||||
dci_pdu_rel15->time_domain_assignment.val = (*dci_pdu >> (dci_size-pos))&0xf;
|
||||
#ifdef DEBUG_EXTRACT_DCI
|
||||
LOG_D(MAC,"time-domain assignment %d (3 bits)=> %d (0x%lx)\n",dci_pdu_rel15->time_domain_assignment.val,dci_size-pos,*dci_pdu);
|
||||
LOG_D(MAC,"time-domain assignment %d (4 bits)=> %d (0x%lx)\n",dci_pdu_rel15->time_domain_assignment.val,dci_size-pos,*dci_pdu);
|
||||
#endif
|
||||
// VRB to PRB mapping
|
||||
|
||||
@@ -3530,7 +3532,7 @@ void nr_extract_dci_info(NR_UE_MAC_INST_t *mac,
|
||||
dci_pdu_rel15->cbgfi.val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->cbgfi.nbits)-1);
|
||||
// DMRS sequence init
|
||||
pos+=1;
|
||||
dci_pdu_rel15->dmrs_sequence_initialization = (*dci_pdu>>(dci_size-pos))&0x1;
|
||||
dci_pdu_rel15->dmrs_sequence_initialization.val = (*dci_pdu>>(dci_size-pos))&0x1;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
@@ -688,7 +688,7 @@ void nr_generate_Msg2(module_id_t module_idP,
|
||||
pdcch_pdu_rel15->StartSymbolIndex,
|
||||
pdcch_pdu_rel15->DurationSymbols);
|
||||
|
||||
fill_dci_pdu_rel15(secondaryCellGroup,pdcch_pdu_rel15, &dci_pdu_rel15[0], dci_formats, rnti_types,dci10_bw,ra->bwp_id);
|
||||
fill_dci_pdu_rel15(scc,secondaryCellGroup,pdcch_pdu_rel15, &dci_pdu_rel15[0], dci_formats, rnti_types,dci10_bw,ra->bwp_id);
|
||||
|
||||
dl_req->nPDUs+=2;
|
||||
|
||||
|
||||
@@ -329,7 +329,7 @@ int configure_fapi_dl_pdu(int Mod_idP,
|
||||
pdsch_pdu_rel15->rbStart = (rbStart!=NULL) ? *rbStart : 0;
|
||||
pdsch_pdu_rel15->rbSize = (rbSize!=NULL) ? *rbSize : pdsch_pdu_rel15->BWPSize;
|
||||
pdsch_pdu_rel15->VRBtoPRBMapping = 1; // non-interleaved, check if this is ok for initialBWP
|
||||
// choose shortest PDSCH
|
||||
|
||||
int startSymbolAndLength=0;
|
||||
int time_domain_assignment=2;
|
||||
int StartSymbolIndex,NrOfSymbols;
|
||||
@@ -362,10 +362,10 @@ int configure_fapi_dl_pdu(int Mod_idP,
|
||||
AssertFatal(1==0,"Only frequency resource allocation type 1 is currently supported\n");
|
||||
// time domain assignment
|
||||
dci_pdu_rel15[0].time_domain_assignment.val = time_domain_assignment; // row index used here instead of SLIV;
|
||||
// mcs ndi and rv
|
||||
// mcs and rv
|
||||
dci_pdu_rel15[0].mcs = pdsch_pdu_rel15->mcsIndex[0];
|
||||
dci_pdu_rel15[0].rv = pdsch_pdu_rel15->rvIndex[0];
|
||||
// harq pid
|
||||
// harq pid and ndi
|
||||
dci_pdu_rel15[0].harq_pid = current_harq_pid;
|
||||
dci_pdu_rel15[0].ndi = UE_list->UE_sched_ctrl[UE_id].harq_processes[current_harq_pid].ndi;
|
||||
// DAI
|
||||
@@ -381,7 +381,8 @@ int configure_fapi_dl_pdu(int Mod_idP,
|
||||
UE_list->UE_sched_ctrl[UE_id].harq_processes[current_harq_pid].is_waiting = 1;
|
||||
// antenna ports
|
||||
dci_pdu_rel15[0].antenna_ports.val = 0; // nb of cdm groups w/o data 1 and dmrs port 0
|
||||
|
||||
// dmrs sequence initialization
|
||||
dci_pdu_rel15[0].dmrs_sequence_initialization.val = pdsch_pdu_rel15->SCID;
|
||||
LOG_D(MAC, "[gNB scheduler phytest] DCI type 1 payload: freq_alloc %d (%d,%d,%d), time_alloc %d, vrb to prb %d, mcs %d tb_scaling %d ndi %d rv %d\n",
|
||||
dci_pdu_rel15[0].frequency_domain_assignment.val,
|
||||
pdsch_pdu_rel15->rbStart,
|
||||
@@ -437,7 +438,7 @@ int configure_fapi_dl_pdu(int Mod_idP,
|
||||
|
||||
rnti_types[0] = NR_RNTI_C;
|
||||
|
||||
fill_dci_pdu_rel15(secondaryCellGroup,pdcch_pdu_rel15,dci_pdu_rel15,dci_formats,rnti_types,pdsch_pdu_rel15->BWPSize,bwp_id);
|
||||
fill_dci_pdu_rel15(scc,secondaryCellGroup,pdcch_pdu_rel15,dci_pdu_rel15,dci_formats,rnti_types,pdsch_pdu_rel15->BWPSize,bwp_id);
|
||||
|
||||
LOG_D(MAC, "DCI params: rnti %x, rnti_type %d, dci_format %d\n \
|
||||
coreset params: FreqDomainResource %llx, start_symbol %d n_symb %d\n",
|
||||
@@ -468,22 +469,70 @@ int configure_fapi_dl_pdu(int Mod_idP,
|
||||
return TBS; //Return TBS in bytes
|
||||
}
|
||||
|
||||
void config_uldci(NR_BWP_Uplink_t *ubwp,nfapi_nr_pusch_pdu_t *pusch_pdu,nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15, dci_pdu_rel15_t *dci_pdu_rel15, int *dci_formats, int *rnti_types) {
|
||||
void config_uldci(NR_BWP_Uplink_t *ubwp,
|
||||
nfapi_nr_pusch_pdu_t *pusch_pdu,
|
||||
nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15,
|
||||
dci_pdu_rel15_t *dci_pdu_rel15,
|
||||
int *dci_formats, int *rnti_types,
|
||||
int time_domain_assignment,
|
||||
int n_ubwp, int bwp_id) {
|
||||
|
||||
dci_pdu_rel15->frequency_domain_assignment.val = PRBalloc_to_locationandbandwidth0(pusch_pdu->rb_size,
|
||||
pusch_pdu->rb_start,
|
||||
NRRIV2BW(ubwp->bwp_Common->genericParameters.locationAndBandwidth,275));
|
||||
switch(dci_formats[(pdcch_pdu_rel15->numDlDci)-1]) {
|
||||
case NR_UL_DCI_FORMAT_0_0:
|
||||
dci_pdu_rel15->frequency_domain_assignment.val = PRBalloc_to_locationandbandwidth0(pusch_pdu->rb_size,
|
||||
pusch_pdu->rb_start,
|
||||
NRRIV2BW(ubwp->bwp_Common->genericParameters.locationAndBandwidth,275));
|
||||
|
||||
dci_pdu_rel15->time_domain_assignment.val = time_domain_assignment;
|
||||
dci_pdu_rel15->frequency_hopping_flag.val = pusch_pdu->frequency_hopping;
|
||||
dci_pdu_rel15->mcs = 9;
|
||||
|
||||
dci_pdu_rel15->format_indicator = 0;
|
||||
dci_pdu_rel15->ndi = 1;
|
||||
dci_pdu_rel15->rv = 0;
|
||||
dci_pdu_rel15->harq_pid = 0;
|
||||
dci_pdu_rel15->tpc = 2;
|
||||
break;
|
||||
case NR_UL_DCI_FORMAT_0_1:
|
||||
dci_pdu_rel15->ndi = pusch_pdu->pusch_data.new_data_indicator;
|
||||
dci_pdu_rel15->rv = pusch_pdu->pusch_data.rv_index;
|
||||
dci_pdu_rel15->harq_pid = pusch_pdu->pusch_data.harq_process_id;
|
||||
dci_pdu_rel15->frequency_hopping_flag.val = pusch_pdu->frequency_hopping;
|
||||
dci_pdu_rel15->dai[0].val = 0; //TODO
|
||||
// bwp indicator
|
||||
if (n_ubwp < 4)
|
||||
dci_pdu_rel15->bwp_indicator.val = bwp_id;
|
||||
else
|
||||
dci_pdu_rel15->bwp_indicator.val = bwp_id - 1; // as per table 7.3.1.1.2-1 in 38.212
|
||||
// frequency domain assignment
|
||||
if (ubwp->bwp_Dedicated->pusch_Config->choice.setup->resourceAllocation==NR_PUSCH_Config__resourceAllocation_resourceAllocationType1)
|
||||
dci_pdu_rel15->frequency_domain_assignment.val = PRBalloc_to_locationandbandwidth0(pusch_pdu->rb_size,
|
||||
pusch_pdu->rb_start,
|
||||
NRRIV2BW(ubwp->bwp_Common->genericParameters.locationAndBandwidth,275));
|
||||
else
|
||||
AssertFatal(1==0,"Only frequency resource allocation type 1 is currently supported\n");
|
||||
// time domain assignment
|
||||
dci_pdu_rel15->time_domain_assignment.val = time_domain_assignment;
|
||||
// mcs
|
||||
dci_pdu_rel15->mcs = pusch_pdu->mcs_index;
|
||||
// tpc command for pusch
|
||||
dci_pdu_rel15->tpc = 2; //TODO
|
||||
// SRS resource indicator
|
||||
if (ubwp->bwp_Dedicated->pusch_Config->choice.setup->txConfig != NULL) {
|
||||
if (*ubwp->bwp_Dedicated->pusch_Config->choice.setup->txConfig == NR_PUSCH_Config__txConfig_codebook)
|
||||
dci_pdu_rel15->srs_resource_indicator.val = 0; // taking resource 0 for SRS
|
||||
else
|
||||
AssertFatal(1==0,"Non Codebook configuration non supported\n");
|
||||
}
|
||||
// Antenna Ports
|
||||
dci_pdu_rel15->antenna_ports.val = 0; // TODO for now it is hardcoded, it should depends on cdm group no data and rank
|
||||
// DMRS sequence initialization
|
||||
dci_pdu_rel15->dmrs_sequence_initialization.val = pusch_pdu->scid;
|
||||
break;
|
||||
default :
|
||||
AssertFatal(1==0,"Valid UL formats are 0_0 and 0_1 \n");
|
||||
}
|
||||
|
||||
dci_pdu_rel15->time_domain_assignment.val = 2; // row index used here instead of SLIV;
|
||||
dci_pdu_rel15->frequency_hopping_flag.val = 0;
|
||||
dci_pdu_rel15->mcs = 9;
|
||||
|
||||
dci_pdu_rel15->format_indicator = 0;
|
||||
dci_pdu_rel15->ndi = 1;
|
||||
dci_pdu_rel15->rv = 0;
|
||||
dci_pdu_rel15->harq_pid = 0;
|
||||
dci_pdu_rel15->tpc = 2;
|
||||
|
||||
LOG_D(MAC, "[gNB scheduler phytest] ULDCI type 0 payload: PDCCH CCEIndex %d, freq_alloc %d, time_alloc %d, freq_hop_flag %d, mcs %d tpc %d ndi %d rv %d\n",
|
||||
pdcch_pdu_rel15->dci_pdu.CceIndex[pdcch_pdu_rel15->numDlDci],
|
||||
dci_pdu_rel15->frequency_domain_assignment.val,
|
||||
@@ -493,10 +542,6 @@ void config_uldci(NR_BWP_Uplink_t *ubwp,nfapi_nr_pusch_pdu_t *pusch_pdu,nfapi_nr
|
||||
dci_pdu_rel15->tpc,
|
||||
dci_pdu_rel15->ndi,
|
||||
dci_pdu_rel15->rv);
|
||||
|
||||
dci_formats[pdcch_pdu_rel15->numDlDci] = NR_UL_DCI_FORMAT_0_0;
|
||||
rnti_types[pdcch_pdu_rel15->numDlDci] = NR_RNTI_C;
|
||||
pdcch_pdu_rel15->numDlDci++;
|
||||
|
||||
}
|
||||
|
||||
@@ -738,7 +783,7 @@ void nr_schedule_uss_ulsch_phytest(int Mod_idP,
|
||||
NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon;
|
||||
|
||||
int bwp_id=1;
|
||||
|
||||
int mu = scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing;
|
||||
int UE_id = 0;
|
||||
NR_UE_list_t *UE_list = &RC.nrmac[Mod_idP]->UE_list;
|
||||
AssertFatal(UE_list->active[UE_id] >=0,"Cannot find UE_id %d is not active\n",UE_id);
|
||||
@@ -748,7 +793,9 @@ void nr_schedule_uss_ulsch_phytest(int Mod_idP,
|
||||
"downlinkBWP_ToAddModList has %d BWP!\n",
|
||||
secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count);
|
||||
NR_BWP_Uplink_t *ubwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_id-1];
|
||||
int n_ubwp = secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count;
|
||||
NR_BWP_Downlink_t *bwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[bwp_id-1];
|
||||
NR_PUSCH_Config_t *pusch_Config = ubwp->bwp_Dedicated->pusch_Config->choice.setup;
|
||||
nfapi_nr_ul_tti_request_t *UL_tti_req = &RC.nrmac[Mod_idP]->UL_tti_req[0];
|
||||
nfapi_nr_ul_dci_request_t *UL_dci_req = &RC.nrmac[Mod_idP]->UL_dci_req[0];
|
||||
|
||||
@@ -769,20 +816,28 @@ void nr_schedule_uss_ulsch_phytest(int Mod_idP,
|
||||
|
||||
LOG_D(MAC, "Scheduling UE specific PUSCH\n");
|
||||
//UL_tti_req = &nr_mac->UL_tti_req[CC_id];
|
||||
/*
|
||||
// original configuration
|
||||
rel15_ul->rnti = 0x1234;
|
||||
rel15_ul->ulsch_pdu_rel15.start_rb = 30;
|
||||
rel15_ul->ulsch_pdu_rel15.number_rbs = 50;
|
||||
rel15_ul->ulsch_pdu_rel15.start_symbol = 2;
|
||||
rel15_ul->ulsch_pdu_rel15.number_symbols = 12;
|
||||
rel15_ul->ulsch_pdu_rel15.nb_re_dmrs = 6;
|
||||
rel15_ul->ulsch_pdu_rel15.length_dmrs = 1;
|
||||
rel15_ul->ulsch_pdu_rel15.Qm = 2;
|
||||
rel15_ul->ulsch_pdu_rel15.mcs = 9;
|
||||
rel15_ul->ulsch_pdu_rel15.rv = 0;
|
||||
rel15_ul->ulsch_pdu_rel15.n_layers = 1;
|
||||
*/
|
||||
|
||||
//Resource Allocation in time domain
|
||||
int startSymbolAndLength=0;
|
||||
int time_domain_assignment=1;
|
||||
int StartSymbolIndex,NrOfSymbols,K2,mapping_type;
|
||||
|
||||
AssertFatal(time_domain_assignment<ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.count,
|
||||
"time_domain_assignment %d>=%d\n",time_domain_assignment,ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.count);
|
||||
startSymbolAndLength = ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[time_domain_assignment]->startSymbolAndLength;
|
||||
SLIV2SL(startSymbolAndLength,&StartSymbolIndex,&NrOfSymbols);
|
||||
pusch_pdu->start_symbol_index = StartSymbolIndex;
|
||||
pusch_pdu->nr_of_symbols = NrOfSymbols;
|
||||
|
||||
mapping_type = ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[time_domain_assignment]->mappingType;
|
||||
if (ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[time_domain_assignment]->k2 != NULL)
|
||||
K2 = *ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[time_domain_assignment]->k2;
|
||||
else {
|
||||
if (mu<2) K2=1;
|
||||
else if(mu==2) K2=2;
|
||||
else K2=3;
|
||||
}
|
||||
|
||||
pusch_pdu->pdu_bit_map = PUSCH_PDU_BITMAP_PUSCH_DATA;
|
||||
pusch_pdu->rnti = rnti;
|
||||
pusch_pdu->handle = 0; //not yet used
|
||||
@@ -797,60 +852,123 @@ void nr_schedule_uss_ulsch_phytest(int Mod_idP,
|
||||
pusch_pdu->mcs_table = 0; //0: notqam256 [TS38.214, table 5.1.3.1-1] - corresponds to nr_target_code_rate_table1 in PHY
|
||||
pusch_pdu->target_code_rate = nr_get_code_rate_ul(pusch_pdu->mcs_index,pusch_pdu->mcs_table) ;
|
||||
pusch_pdu->qam_mod_order = nr_get_Qm_ul(pusch_pdu->mcs_index,pusch_pdu->mcs_table) ;
|
||||
pusch_pdu->transform_precoding = 0;
|
||||
pusch_pdu->data_scrambling_id = 0; //It equals the higher-layer parameter Data-scrambling-Identity if configured and the RNTI equals the C-RNTI, otherwise L2 needs to set it to physical cell id.;
|
||||
if (pusch_Config->transformPrecoder == NULL) {
|
||||
if (scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder == NULL)
|
||||
pusch_pdu->transform_precoding = 1;
|
||||
else
|
||||
pusch_pdu->transform_precoding = 0;
|
||||
}
|
||||
else
|
||||
pusch_pdu->transform_precoding = *pusch_Config->transformPrecoder;
|
||||
if (pusch_Config->dataScramblingIdentityPUSCH != NULL)
|
||||
pusch_pdu->data_scrambling_id = *pusch_Config->dataScramblingIdentityPUSCH;
|
||||
else
|
||||
pusch_pdu->data_scrambling_id = *scc->physCellId;
|
||||
|
||||
pusch_pdu->nrOfLayers = 1;
|
||||
|
||||
//Pusch Allocation in frequency domain [TS38.214, sec 6.1.2.2]
|
||||
pusch_pdu->resource_alloc = 1; //type 1
|
||||
//pusch_pdu->rb_bitmap;// for ressource alloc type 0
|
||||
pusch_pdu->rb_start = 0;
|
||||
pusch_pdu->rb_size = 50;
|
||||
if (pusch_Config->resourceAllocation==NR_PUSCH_Config__resourceAllocation_resourceAllocationType1) {
|
||||
pusch_pdu->resource_alloc = 1; //type 1
|
||||
pusch_pdu->rb_start = 0;
|
||||
pusch_pdu->rb_size = 50;
|
||||
}
|
||||
else
|
||||
AssertFatal(1==0,"Only frequency resource allocation type 1 is currently supported\n");
|
||||
|
||||
pusch_pdu->vrb_to_prb_mapping = 0;
|
||||
pusch_pdu->frequency_hopping = 0;
|
||||
|
||||
if (pusch_Config->frequencyHopping==NULL)
|
||||
pusch_pdu->frequency_hopping = 0;
|
||||
else
|
||||
pusch_pdu->frequency_hopping = 1;
|
||||
|
||||
//pusch_pdu->tx_direct_current_location;//The uplink Tx Direct Current location for the carrier. Only values in the value range of this field between 0 and 3299, which indicate the subcarrier index within the carrier corresponding 1o the numerology of the corresponding uplink BWP and value 3300, which indicates "Outside the carrier" and value 3301, which indicates "Undetermined position within the carrier" are used. [TS38.331, UplinkTxDirectCurrentBWP IE]
|
||||
pusch_pdu->uplink_frequency_shift_7p5khz = 0;
|
||||
//Resource Allocation in time domain
|
||||
pusch_pdu->start_symbol_index = 2;
|
||||
pusch_pdu->nr_of_symbols = 12;
|
||||
//pusch_pdu->uplink_frequency_shift_7p5khz = 0;
|
||||
|
||||
|
||||
// --------------------
|
||||
// ------- DMRS -------
|
||||
// --------------------
|
||||
uint16_t l_prime_mask = get_l_prime(pusch_pdu->nr_of_symbols, typeB, pusch_dmrs_pos0, pusch_len1);
|
||||
pusch_pdu->ul_dmrs_symb_pos = l_prime_mask << pusch_pdu->start_symbol_index;
|
||||
pusch_pdu->dmrs_config_type = 0; // dmrs-type 1 (the one with a single DMRS symbol in the beginning)
|
||||
pusch_pdu->ul_dmrs_scrambling_id = 0; // If provided and the PUSCH is not a msg3 PUSCH, otherwise, L2 should set this to physical cell id
|
||||
pusch_pdu->scid = 0; // DMRS sequence initialization [TS38.211, sec 6.4.1.1.1]
|
||||
// Should match what is sent in DCI 0_1, otherwise set to 0
|
||||
NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig;
|
||||
if (mapping_type == NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeA)
|
||||
NR_DMRS_UplinkConfig = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup;
|
||||
else
|
||||
NR_DMRS_UplinkConfig = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup;
|
||||
if (NR_DMRS_UplinkConfig->dmrs_Type == NULL)
|
||||
pusch_pdu->dmrs_config_type = 0;
|
||||
else
|
||||
pusch_pdu->dmrs_config_type = 1;
|
||||
pusch_pdu->scid = 0; // DMRS sequence initialization [TS38.211, sec 6.4.1.1.1]
|
||||
if (pusch_pdu->transform_precoding) { // transform precoding disabled
|
||||
long *scramblingid;
|
||||
if (pusch_pdu->scid == 0)
|
||||
scramblingid = NR_DMRS_UplinkConfig->transformPrecodingDisabled->scramblingID0;
|
||||
else
|
||||
scramblingid = NR_DMRS_UplinkConfig->transformPrecodingDisabled->scramblingID1;
|
||||
if (scramblingid == NULL)
|
||||
pusch_pdu->ul_dmrs_scrambling_id = *scc->physCellId;
|
||||
else
|
||||
pusch_pdu->ul_dmrs_scrambling_id = *scramblingid;
|
||||
}
|
||||
else {
|
||||
pusch_pdu->ul_dmrs_scrambling_id = *scc->physCellId;
|
||||
if (NR_DMRS_UplinkConfig->transformPrecodingEnabled->nPUSCH_Identity != NULL)
|
||||
pusch_pdu->pusch_identity = *NR_DMRS_UplinkConfig->transformPrecodingEnabled->nPUSCH_Identity;
|
||||
else
|
||||
pusch_pdu->pusch_identity = *scc->physCellId;
|
||||
}
|
||||
pusch_dmrs_AdditionalPosition_t additional_pos;
|
||||
if (NR_DMRS_UplinkConfig->dmrs_AdditionalPosition == NULL)
|
||||
additional_pos = 2;
|
||||
else {
|
||||
if (*NR_DMRS_UplinkConfig->dmrs_AdditionalPosition == NR_DMRS_UplinkConfig__dmrs_AdditionalPosition_pos3)
|
||||
additional_pos = 3;
|
||||
else
|
||||
additional_pos = *NR_DMRS_UplinkConfig->dmrs_AdditionalPosition;
|
||||
}
|
||||
pusch_maxLength_t pusch_maxLength;
|
||||
if (NR_DMRS_UplinkConfig->maxLength == NULL)
|
||||
pusch_maxLength = 1;
|
||||
else
|
||||
pusch_maxLength = 2;
|
||||
uint16_t l_prime_mask = get_l_prime(pusch_pdu->nr_of_symbols, mapping_type, additional_pos, pusch_maxLength);
|
||||
pusch_pdu->ul_dmrs_symb_pos = l_prime_mask << pusch_pdu->start_symbol_index;
|
||||
|
||||
pusch_pdu->num_dmrs_cdm_grps_no_data = 1;
|
||||
//pusch_pdu->dmrs_ports; // DMRS ports. [TS38.212 7.3.1.1.2] provides description between DCI 0-1 content and DMRS ports
|
||||
// Bitmap occupying the 11 LSBs with: bit 0: antenna port 1000 bit 11: antenna port 1011,
|
||||
// and for each bit 0: DMRS port not used 1: DMRS port used
|
||||
pusch_pdu->dmrs_ports = 1;
|
||||
// --------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// --------------------
|
||||
// ------- PTRS -------
|
||||
// --------------------
|
||||
uint8_t ptrs_mcs1 = 2; // higher layer parameter in PTRS-UplinkConfig
|
||||
uint8_t ptrs_mcs2 = 4; // higher layer parameter in PTRS-UplinkConfig
|
||||
uint8_t ptrs_mcs3 = 10; // higher layer parameter in PTRS-UplinkConfig
|
||||
uint16_t n_rb0 = 25; // higher layer parameter in PTRS-UplinkConfig
|
||||
uint16_t n_rb1 = 75; // higher layer parameter in PTRS-UplinkConfig
|
||||
pusch_pdu->pusch_ptrs.ptrs_time_density = get_L_ptrs(ptrs_mcs1, ptrs_mcs2, ptrs_mcs3, pusch_pdu->mcs_index, pusch_pdu->mcs_table);
|
||||
pusch_pdu->pusch_ptrs.ptrs_freq_density = get_K_ptrs(n_rb0, n_rb1, pusch_pdu->rb_size);
|
||||
pusch_pdu->pusch_ptrs.ptrs_ports_list = (nfapi_nr_ptrs_ports_t *) malloc(2*sizeof(nfapi_nr_ptrs_ports_t));
|
||||
pusch_pdu->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset = 0;
|
||||
if (NR_DMRS_UplinkConfig->phaseTrackingRS != NULL) {
|
||||
// TODO to be fixed from RRC config
|
||||
uint8_t ptrs_mcs1 = 2; // higher layer parameter in PTRS-UplinkConfig
|
||||
uint8_t ptrs_mcs2 = 4; // higher layer parameter in PTRS-UplinkConfig
|
||||
uint8_t ptrs_mcs3 = 10; // higher layer parameter in PTRS-UplinkConfig
|
||||
uint16_t n_rb0 = 25; // higher layer parameter in PTRS-UplinkConfig
|
||||
uint16_t n_rb1 = 75; // higher layer parameter in PTRS-UplinkConfig
|
||||
pusch_pdu->pusch_ptrs.ptrs_time_density = get_L_ptrs(ptrs_mcs1, ptrs_mcs2, ptrs_mcs3, pusch_pdu->mcs_index, pusch_pdu->mcs_table);
|
||||
pusch_pdu->pusch_ptrs.ptrs_freq_density = get_K_ptrs(n_rb0, n_rb1, pusch_pdu->rb_size);
|
||||
pusch_pdu->pusch_ptrs.ptrs_ports_list = (nfapi_nr_ptrs_ports_t *) malloc(2*sizeof(nfapi_nr_ptrs_ports_t));
|
||||
pusch_pdu->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset = 0;
|
||||
|
||||
pusch_pdu->pdu_bit_map &= PUSCH_PDU_BITMAP_PUSCH_PTRS; // enable PUSCH PTRS
|
||||
}
|
||||
else{
|
||||
// if(1<<pusch_pdu->pusch_ptrs.ptrs_time_density >= pusch_pdu->nr_of_symbols)
|
||||
pusch_pdu->pdu_bit_map &= ~PUSCH_PDU_BITMAP_PUSCH_PTRS; // disable PUSCH PTRS
|
||||
}
|
||||
|
||||
if(1<<pusch_pdu->pusch_ptrs.ptrs_time_density >= pusch_pdu->nr_of_symbols)
|
||||
pusch_pdu->pdu_bit_map &= ~PUSCH_PDU_BITMAP_PUSCH_PTRS; // disable PUSCH PTRS
|
||||
// --------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
//Pusch Allocation in frequency domain [TS38.214, sec 6.1.2.2]
|
||||
//Optional Data only included if indicated in pduBitmap
|
||||
// TODO from harq function as in pdsch
|
||||
pusch_pdu->pusch_data.rv_index = 0;
|
||||
pusch_pdu->pusch_data.harq_process_id = 0;
|
||||
pusch_pdu->pusch_data.new_data_indicator = 0;
|
||||
pusch_pdu->pusch_data.new_data_indicator = 1;
|
||||
|
||||
uint8_t num_dmrs_symb = 0;
|
||||
|
||||
@@ -935,9 +1053,10 @@ void nr_schedule_uss_ulsch_phytest(int Mod_idP,
|
||||
return;
|
||||
}
|
||||
else {
|
||||
dci_pdu_rel15_t dci_pdu_rel15[MAX_DCI_CORESET];
|
||||
config_uldci(ubwp,pusch_pdu,pdcch_pdu_rel15, &dci_pdu_rel15[0], dci_formats, rnti_types);
|
||||
fill_dci_pdu_rel15(secondaryCellGroup,pdcch_pdu_rel15,dci_pdu_rel15,dci_formats,rnti_types,pusch_pdu->bwp_size,bwp_id);
|
||||
dci_pdu_rel15_t *dci_pdu_rel15 = calloc(MAX_DCI_CORESET,sizeof(dci_pdu_rel15_t));
|
||||
config_uldci(ubwp,pusch_pdu,pdcch_pdu_rel15,&dci_pdu_rel15[0],dci_formats,rnti_types,time_domain_assignment,n_ubwp,bwp_id);
|
||||
fill_dci_pdu_rel15(scc,secondaryCellGroup,pdcch_pdu_rel15,dci_pdu_rel15,dci_formats,rnti_types,pusch_pdu->bwp_size,bwp_id);
|
||||
free(dci_pdu_rel15);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -68,8 +68,6 @@
|
||||
|
||||
extern RAN_CONTEXT_t RC;
|
||||
|
||||
extern int n_active_slices;
|
||||
|
||||
// Note the 2 scs values in the table names represent resp. scs_common and pdcch_scs
|
||||
/// LUT for the number of symbols in the coreset indexed by coreset index (4 MSB rmsi_pdcch_config)
|
||||
uint8_t nr_coreset_nsymb_pdcch_type_0_scs_15_15[15] = {2,2,2,3,3,3,1,1,2,2,3,3,1,2,3};
|
||||
@@ -734,6 +732,19 @@ void prepare_dci(NR_CellGroupConfig_t *secondaryCellGroup,
|
||||
NR_BWP_Downlink_t *bwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[bwp_id-1];
|
||||
|
||||
switch(format) {
|
||||
case NR_UL_DCI_FORMAT_0_1:
|
||||
// format indicator
|
||||
dci_pdu_rel15->format_indicator = 0;
|
||||
// carrier indicator
|
||||
if (secondaryCellGroup->spCellConfig->spCellConfigDedicated->crossCarrierSchedulingConfig != NULL)
|
||||
AssertFatal(1==0,"Cross Carrier Scheduling Config currently not supported\n");
|
||||
// supplementary uplink
|
||||
if (secondaryCellGroup->spCellConfig->spCellConfigDedicated->supplementaryUplink != NULL)
|
||||
AssertFatal(1==0,"Supplementary Uplink currently not supported\n");
|
||||
// SRS request
|
||||
dci_pdu_rel15->srs_request.val = 0;
|
||||
dci_pdu_rel15->ulsch_indicator = 1;
|
||||
break;
|
||||
case NR_DL_DCI_FORMAT_1_1:
|
||||
// format indicator
|
||||
dci_pdu_rel15->format_indicator = 1;
|
||||
@@ -782,16 +793,15 @@ void prepare_dci(NR_CellGroupConfig_t *secondaryCellGroup,
|
||||
// CBGTI and CBGFI
|
||||
if (secondaryCellGroup->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup->codeBlockGroupTransmission != NULL)
|
||||
AssertFatal(1==0,"CBG transmission currently not supported\n");
|
||||
// dmrs sequence initialization
|
||||
dci_pdu_rel15->dmrs_sequence_initialization = 0; // FIXME no information on what this bit should be in 38.212
|
||||
break;
|
||||
default :
|
||||
AssertFatal(1==0,"Prepare dci currently only implemented for 1_1 \n");
|
||||
AssertFatal(1==0,"Prepare dci currently only implemented for 1_1 and 0_1 \n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void fill_dci_pdu_rel15(NR_CellGroupConfig_t *secondaryCellGroup,
|
||||
void fill_dci_pdu_rel15(NR_ServingCellConfigCommon_t *scc,
|
||||
NR_CellGroupConfig_t *secondaryCellGroup,
|
||||
nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15,
|
||||
dci_pdu_rel15_t *dci_pdu_rel15,
|
||||
int *dci_formats,
|
||||
@@ -804,11 +814,11 @@ void fill_dci_pdu_rel15(NR_CellGroupConfig_t *secondaryCellGroup,
|
||||
for (int d=0;d<pdcch_pdu_rel15->numDlDci;d++) {
|
||||
|
||||
uint64_t *dci_pdu = (uint64_t *)pdcch_pdu_rel15->dci_pdu.Payload[d];
|
||||
int dci_size = nr_dci_size(secondaryCellGroup,&dci_pdu_rel15[d],dci_formats[d],rnti_types[d],N_RB,bwp_id);
|
||||
int dci_size = nr_dci_size(scc,secondaryCellGroup,&dci_pdu_rel15[d],dci_formats[d],rnti_types[d],N_RB,bwp_id);
|
||||
pdcch_pdu_rel15->dci_pdu.PayloadSizeBits[d] = dci_size;
|
||||
AssertFatal(pdcch_pdu_rel15->dci_pdu.PayloadSizeBits[d]<=64, "DCI sizes above 64 bits not yet supported");
|
||||
|
||||
if(dci_formats[d]==NR_DL_DCI_FORMAT_1_1)
|
||||
if(dci_formats[d]==NR_DL_DCI_FORMAT_1_1 || dci_formats[d]==NR_UL_DCI_FORMAT_0_1)
|
||||
prepare_dci(secondaryCellGroup,&dci_pdu_rel15[d],dci_formats[d],bwp_id);
|
||||
|
||||
/// Payload generation
|
||||
@@ -1118,6 +1128,110 @@ void fill_dci_pdu_rel15(NR_CellGroupConfig_t *secondaryCellGroup,
|
||||
}
|
||||
break;
|
||||
|
||||
case NR_UL_DCI_FORMAT_0_1:
|
||||
switch(rnti_types[d])
|
||||
{
|
||||
case NR_RNTI_C:
|
||||
// Indicating a DL DCI format 1bit
|
||||
pos=1;
|
||||
*dci_pdu |= ((uint64_t)dci_pdu_rel15->format_indicator&0x1)<<(dci_size-pos);
|
||||
|
||||
// Carrier indicator
|
||||
pos+=dci_pdu_rel15->carrier_indicator.nbits;
|
||||
*dci_pdu |= ((uint64_t)dci_pdu_rel15->carrier_indicator.val&((1<<dci_pdu_rel15->carrier_indicator.nbits)-1))<<(dci_size-pos);
|
||||
|
||||
// UL/SUL Indicator
|
||||
pos+=dci_pdu_rel15->ul_sul_indicator.nbits;
|
||||
*dci_pdu |= ((uint64_t)dci_pdu_rel15->ul_sul_indicator.val&((1<<dci_pdu_rel15->ul_sul_indicator.nbits)-1))<<(dci_size-pos);
|
||||
|
||||
// BWP indicator
|
||||
pos+=dci_pdu_rel15->bwp_indicator.nbits;
|
||||
*dci_pdu |= ((uint64_t)dci_pdu_rel15->bwp_indicator.val&((1<<dci_pdu_rel15->bwp_indicator.nbits)-1))<<(dci_size-pos);
|
||||
|
||||
// Frequency domain resource assignment
|
||||
pos+=dci_pdu_rel15->frequency_domain_assignment.nbits;
|
||||
*dci_pdu |= ((uint64_t)dci_pdu_rel15->frequency_domain_assignment.val&((1<<dci_pdu_rel15->frequency_domain_assignment.nbits)-1)) << (dci_size-pos);
|
||||
|
||||
// Time domain resource assignment
|
||||
pos+=dci_pdu_rel15->time_domain_assignment.nbits;
|
||||
*dci_pdu |= ((uint64_t)dci_pdu_rel15->time_domain_assignment.val&((1<<dci_pdu_rel15->time_domain_assignment.nbits)-1)) << (dci_size-pos);
|
||||
|
||||
// Frequency hopping
|
||||
pos+=dci_pdu_rel15->frequency_hopping_flag.nbits;
|
||||
*dci_pdu |= ((uint64_t)dci_pdu_rel15->frequency_hopping_flag.val&((1<<dci_pdu_rel15->frequency_hopping_flag.nbits)-1)) << (dci_size-pos);
|
||||
|
||||
// MCS 5bit
|
||||
pos+=5;
|
||||
*dci_pdu |= ((uint64_t)dci_pdu_rel15->mcs&0x1f)<<(dci_size-pos);
|
||||
|
||||
// New data indicator 1bit
|
||||
pos+=1;
|
||||
*dci_pdu |= ((uint64_t)dci_pdu_rel15->ndi&0x1)<<(dci_size-pos);
|
||||
|
||||
// Redundancy version 2bit
|
||||
pos+=2;
|
||||
*dci_pdu |= ((uint64_t)dci_pdu_rel15->rv&0x3)<<(dci_size-pos);
|
||||
|
||||
// HARQ process number 4bit
|
||||
pos+=4;
|
||||
*dci_pdu |= ((uint64_t)dci_pdu_rel15->harq_pid&0xf)<<(dci_size-pos);
|
||||
|
||||
// 1st Downlink assignment index
|
||||
pos+=dci_pdu_rel15->dai[0].nbits;
|
||||
*dci_pdu |= ((uint64_t)dci_pdu_rel15->dai[0].val&((1<<dci_pdu_rel15->dai[0].nbits)-1))<<(dci_size-pos);
|
||||
|
||||
// 2nd Downlink assignment index
|
||||
pos+=dci_pdu_rel15->dai[1].nbits;
|
||||
*dci_pdu |= ((uint64_t)dci_pdu_rel15->dai[1].val&((1<<dci_pdu_rel15->dai[1].nbits)-1))<<(dci_size-pos);
|
||||
|
||||
// TPC command for scheduled PUSCH 2bit
|
||||
pos+=2;
|
||||
*dci_pdu |= ((uint64_t)dci_pdu_rel15->tpc&0x3)<<(dci_size-pos);
|
||||
|
||||
// SRS resource indicator
|
||||
pos+=dci_pdu_rel15->srs_resource_indicator.nbits;
|
||||
*dci_pdu |= ((uint64_t)dci_pdu_rel15->srs_resource_indicator.val&((1<<dci_pdu_rel15->srs_resource_indicator.nbits)-1))<<(dci_size-pos);
|
||||
|
||||
// Precoding info and n. of layers
|
||||
pos+=dci_pdu_rel15->precoding_information.nbits;
|
||||
*dci_pdu |= ((uint64_t)dci_pdu_rel15->precoding_information.val&((1<<dci_pdu_rel15->precoding_information.nbits)-1))<<(dci_size-pos);
|
||||
|
||||
// Antenna ports
|
||||
pos+=dci_pdu_rel15->antenna_ports.nbits;
|
||||
*dci_pdu |= ((uint64_t)dci_pdu_rel15->antenna_ports.val&((1<<dci_pdu_rel15->antenna_ports.nbits)-1))<<(dci_size-pos);
|
||||
|
||||
// SRS request
|
||||
pos+=dci_pdu_rel15->srs_request.nbits;
|
||||
*dci_pdu |= ((uint64_t)dci_pdu_rel15->srs_request.val&((1<<dci_pdu_rel15->srs_request.nbits)-1))<<(dci_size-pos);
|
||||
|
||||
// CSI request
|
||||
pos+=dci_pdu_rel15->csi_request.nbits;
|
||||
*dci_pdu |= ((uint64_t)dci_pdu_rel15->csi_request.val&((1<<dci_pdu_rel15->csi_request.nbits)-1))<<(dci_size-pos);
|
||||
|
||||
// CBG transmission information
|
||||
pos+=dci_pdu_rel15->cbgti.nbits;
|
||||
*dci_pdu |= ((uint64_t)dci_pdu_rel15->cbgti.val&((1<<dci_pdu_rel15->cbgti.nbits)-1))<<(dci_size-pos);
|
||||
|
||||
// PTRS DMRS association
|
||||
pos+=dci_pdu_rel15->ptrs_dmrs_association.nbits;
|
||||
*dci_pdu |= ((uint64_t)dci_pdu_rel15->ptrs_dmrs_association.val&((1<<dci_pdu_rel15->ptrs_dmrs_association.nbits)-1))<<(dci_size-pos);
|
||||
|
||||
// Beta offset indicator
|
||||
pos+=dci_pdu_rel15->beta_offset_indicator.nbits;
|
||||
*dci_pdu |= ((uint64_t)dci_pdu_rel15->beta_offset_indicator.val&((1<<dci_pdu_rel15->beta_offset_indicator.nbits)-1))<<(dci_size-pos);
|
||||
|
||||
// DMRS sequence initialization
|
||||
pos+=dci_pdu_rel15->dmrs_sequence_initialization.nbits;
|
||||
*dci_pdu |= ((uint64_t)dci_pdu_rel15->dmrs_sequence_initialization.val&((1<<dci_pdu_rel15->dmrs_sequence_initialization.nbits)-1))<<(dci_size-pos);
|
||||
|
||||
// UL-SCH indicator
|
||||
pos+=1;
|
||||
*dci_pdu |= ((uint64_t)dci_pdu_rel15->ulsch_indicator&0x1)<<(dci_size-pos);
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case NR_DL_DCI_FORMAT_1_1:
|
||||
// Indicating a DL DCI format 1bit
|
||||
pos=1;
|
||||
@@ -1223,7 +1337,7 @@ void fill_dci_pdu_rel15(NR_CellGroupConfig_t *secondaryCellGroup,
|
||||
|
||||
// DMRS sequence init
|
||||
pos+=1;
|
||||
*dci_pdu |= ((uint64_t)dci_pdu_rel15->dmrs_sequence_initialization&0x1)<<(dci_size-pos);
|
||||
*dci_pdu |= ((uint64_t)dci_pdu_rel15->dmrs_sequence_initialization.val&0x1)<<(dci_size-pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,7 +132,13 @@ int configure_fapi_dl_pdu(int Mod_id,
|
||||
uint16_t *rbSize,
|
||||
uint16_t *rbStart);
|
||||
|
||||
void config_uldci(NR_BWP_Uplink_t *ubwp,nfapi_nr_pusch_pdu_t *pusch_pdu,nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15, dci_pdu_rel15_t *dci_pdu_rel15, int *dci_formats, int *rnti_types);
|
||||
void config_uldci(NR_BWP_Uplink_t *ubwp,
|
||||
nfapi_nr_pusch_pdu_t *pusch_pdu,
|
||||
nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15,
|
||||
dci_pdu_rel15_t *dci_pdu_rel15,
|
||||
int *dci_formats, int *rnti_types,
|
||||
int time_domain_assignment,
|
||||
int n_ubwp, int bwp_id);
|
||||
|
||||
void configure_fapi_dl_Tx(module_id_t Mod_idP,
|
||||
frame_t frameP,
|
||||
@@ -203,7 +209,8 @@ int nr_configure_pdcch(gNB_MAC_INST *nr_mac,
|
||||
NR_ServingCellConfigCommon_t *scc,
|
||||
NR_BWP_Downlink_t *bwp);
|
||||
|
||||
void fill_dci_pdu_rel15(NR_CellGroupConfig_t *secondaryCellGroup,
|
||||
void fill_dci_pdu_rel15(NR_ServingCellConfigCommon_t *scc,
|
||||
NR_CellGroupConfig_t *secondaryCellGroup,
|
||||
nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15,
|
||||
dci_pdu_rel15_t *dci_pdu_rel15,
|
||||
int *dci_formats,
|
||||
@@ -289,6 +296,8 @@ void nr_process_mac_pdu(
|
||||
uint8_t *pduP,
|
||||
uint16_t mac_pdu_len);
|
||||
|
||||
int binomial(int n, int k);
|
||||
|
||||
|
||||
/* \brief Function to indicate a received SDU on ULSCH.
|
||||
@param Mod_id Instance ID of gNB
|
||||
|
||||
@@ -114,7 +114,9 @@ int pdcp_fifo_flush_sdus(const protocol_ctxt_t *const ctxt_pP) {
|
||||
int ret=0;
|
||||
while ((sdu_p = pollNotifiedFIFO(&pdcp_sdu_list)) != NULL ) {
|
||||
pdcp_data_ind_header_t * pdcpHead=(pdcp_data_ind_header_t *)NotifiedFifoData(sdu_p);
|
||||
AssertFatal(pdcpHead->inst==ctxt_pP->module_id, "To implement correctly multi module id\n");
|
||||
|
||||
/* Note: we ignore the instance ID in the context and use the one in the
|
||||
* PDCP packet to pick the right socket below */
|
||||
|
||||
int rb_id = pdcpHead->rb_id;
|
||||
int sizeToWrite= sizeof (pdcp_data_ind_header_t) +
|
||||
@@ -130,19 +132,19 @@ int pdcp_fifo_flush_sdus(const protocol_ctxt_t *const ctxt_pP) {
|
||||
sizeof(sidelink_pc5s_element), 0, (struct sockaddr *)&prose_pdcp_addr,sizeof(prose_pdcp_addr) );
|
||||
|
||||
} else if (UE_NAS_USE_TUN) {
|
||||
//ret = write(nas_sock_fd[ctxt_pP->module_id], &(sdu_p->data[sizeof(pdcp_data_ind_header_t)]),sizeToWrite );
|
||||
//ret = write(nas_sock_fd[pdcpHead->inst], &(sdu_p->data[sizeof(pdcp_data_ind_header_t)]),sizeToWrite );
|
||||
if(rb_id == mbms_rab_id){
|
||||
ret = write(nas_sock_mbms_fd, pdcpData,sizeToWrite );
|
||||
LOG_I(PDCP,"[PDCP_FIFOS] ret %d TRIED TO PUSH MBMS DATA TO rb_id %d handle %d sizeToWrite %d\n",
|
||||
ret,rb_id,nas_sock_fd[ctxt_pP->module_id],sizeToWrite);
|
||||
ret,rb_id,nas_sock_fd[pdcpHead->inst],sizeToWrite);
|
||||
}
|
||||
else
|
||||
{
|
||||
if( LOG_DEBUGFLAG(DEBUG_PDCP) )
|
||||
log_dump(PDCP, pdcpData, sizeToWrite, LOG_DUMP_CHAR,"PDCP output to be sent to TUN interface: \n");
|
||||
ret = write(nas_sock_fd[ctxt_pP->module_id], pdcpData,sizeToWrite );
|
||||
ret = write(nas_sock_fd[pdcpHead->inst], pdcpData,sizeToWrite );
|
||||
LOG_T(PDCP,"[UE PDCP_FIFOS] ret %d TRIED TO PUSH DATA TO rb_id %d handle %d sizeToWrite %d\n",
|
||||
ret,rb_id,nas_sock_fd[ctxt_pP->module_id],sizeToWrite);
|
||||
ret,rb_id,nas_sock_fd[pdcpHead->inst],sizeToWrite);
|
||||
}
|
||||
} else if (ENB_NAS_USE_TUN) {
|
||||
if( LOG_DEBUGFLAG(DEBUG_PDCP) )
|
||||
|
||||
@@ -2310,7 +2310,7 @@ uint8_t do_SidelinkUEInformation(uint8_t Mod_id, uint8_t *buffer, LTE_SL_Destin
|
||||
return((enc_rval.encoded+7)/8);
|
||||
}
|
||||
|
||||
uint8_t do_RRCConnectionSetupComplete(uint8_t Mod_id, uint8_t *buffer, const uint8_t Transaction_id, const int dedicatedInfoNASLength, const char *dedicatedInfoNAS) {
|
||||
uint8_t do_RRCConnectionSetupComplete(uint8_t Mod_id, uint8_t *buffer, const uint8_t Transaction_id, uint8_t sel_plmn_id, const int dedicatedInfoNASLength, const char *dedicatedInfoNAS) {
|
||||
asn_enc_rval_t enc_rval;
|
||||
LTE_UL_DCCH_Message_t ul_dcch_msg;
|
||||
LTE_RRCConnectionSetupComplete_t *rrcConnectionSetupComplete;
|
||||
@@ -2323,7 +2323,7 @@ uint8_t do_RRCConnectionSetupComplete(uint8_t Mod_id, uint8_t *buffer, const uin
|
||||
rrcConnectionSetupComplete->criticalExtensions.choice.c1.present = LTE_RRCConnectionSetupComplete__criticalExtensions__c1_PR_rrcConnectionSetupComplete_r8;
|
||||
rrcConnectionSetupComplete->criticalExtensions.choice.c1.choice.rrcConnectionSetupComplete_r8.nonCriticalExtension=CALLOC(1,
|
||||
sizeof(*rrcConnectionSetupComplete->criticalExtensions.choice.c1.choice.rrcConnectionSetupComplete_r8.nonCriticalExtension));
|
||||
rrcConnectionSetupComplete->criticalExtensions.choice.c1.choice.rrcConnectionSetupComplete_r8.selectedPLMN_Identity= 1;
|
||||
rrcConnectionSetupComplete->criticalExtensions.choice.c1.choice.rrcConnectionSetupComplete_r8.selectedPLMN_Identity= sel_plmn_id;
|
||||
rrcConnectionSetupComplete->criticalExtensions.choice.c1.choice.rrcConnectionSetupComplete_r8.registeredMME =
|
||||
NULL;//calloc(1,sizeof(*rrcConnectionSetupComplete->criticalExtensions.choice.c1.choice.rrcConnectionSetupComplete_r8.registeredMME));
|
||||
/*
|
||||
|
||||
@@ -142,7 +142,11 @@ uint8_t do_SidelinkUEInformation(uint8_t Mod_id, uint8_t *buffer, LTE_SL_Destina
|
||||
/** \brief Generate an RRCConnectionSetupComplete UL-DCCH-Message (UE)
|
||||
@param buffer Pointer to PER-encoded ASN.1 description of UL-DCCH-Message PDU
|
||||
@returns Size of encoded bit stream in bytes*/
|
||||
uint8_t do_RRCConnectionSetupComplete(uint8_t Mod_id, uint8_t *buffer, const uint8_t Transaction_id, const int dedicatedInfoNASLength,
|
||||
uint8_t do_RRCConnectionSetupComplete(uint8_t Mod_id,
|
||||
uint8_t *buffer,
|
||||
const uint8_t Transaction_id,
|
||||
uint8_t sel_plmn_id,
|
||||
const int dedicatedInfoNASLength,
|
||||
const char *dedicatedInfoNAS);
|
||||
|
||||
/** \brief Generate an RRCConnectionReconfigurationComplete UL-DCCH-Message (UE)
|
||||
|
||||
+53
-38
@@ -128,8 +128,13 @@ static int decode_SIB1_MBMS( const protocol_ctxt_t *const ctxt_pP, const uint8_t
|
||||
* \param ctxt_pP Running context
|
||||
* \param eNB_index Index of corresponding eNB/CH
|
||||
* \param Transaction_id Transaction identifier
|
||||
* \param sel_plmn_id selected PLMN Identity
|
||||
*/
|
||||
static void rrc_ue_generate_RRCConnectionSetupComplete( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index, const uint8_t Transaction_id );
|
||||
static void rrc_ue_generate_RRCConnectionSetupComplete(
|
||||
const protocol_ctxt_t *const ctxt_pP,
|
||||
const uint8_t eNB_index,
|
||||
const uint8_t Transaction_id,
|
||||
uint8_t sel_plmn_id);
|
||||
|
||||
/** \brief Generates/Encodes RRCConnectionReconfigurationComplete message at UE
|
||||
* \param ctxt_pP Running context
|
||||
@@ -367,6 +372,7 @@ char openair_rrc_ue_init( const module_id_t ue_mod_idP, const unsigned char eNB_
|
||||
rrc_set_state (ue_mod_idP, RRC_STATE_INACTIVE);
|
||||
rrc_set_sub_state (ue_mod_idP, RRC_SUB_STATE_INACTIVE);
|
||||
LOG_I(RRC,"[UE %d] INIT State = RRC_IDLE (eNB %d)\n",ctxt.module_id,eNB_index);
|
||||
UE_rrc_inst[ctxt.module_id].selected_plmn_identity = 1;
|
||||
UE_rrc_inst[ctxt.module_id].Info[eNB_index].State=RRC_IDLE;
|
||||
UE_rrc_inst[ctxt.module_id].Info[eNB_index].T300_active = 0;
|
||||
UE_rrc_inst[ctxt.module_id].Info[eNB_index].T304_active = 0;
|
||||
@@ -490,7 +496,11 @@ rrc_t310_expiration(
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
static void rrc_ue_generate_RRCConnectionSetupComplete( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index, const uint8_t Transaction_id ) {
|
||||
static void rrc_ue_generate_RRCConnectionSetupComplete(
|
||||
const protocol_ctxt_t *const ctxt_pP,
|
||||
const uint8_t eNB_index,
|
||||
const uint8_t Transaction_id,
|
||||
uint8_t sel_plmn_id) {
|
||||
uint8_t buffer[100];
|
||||
uint8_t size;
|
||||
const char *nas_msg;
|
||||
@@ -504,7 +514,7 @@ static void rrc_ue_generate_RRCConnectionSetupComplete( const protocol_ctxt_t *c
|
||||
nas_msg_length = sizeof(nas_attach_req_imsi);
|
||||
}
|
||||
|
||||
size = do_RRCConnectionSetupComplete(ctxt_pP->module_id, buffer, Transaction_id, nas_msg_length, nas_msg);
|
||||
size = do_RRCConnectionSetupComplete(ctxt_pP->module_id, buffer, Transaction_id, sel_plmn_id, nas_msg_length, nas_msg);
|
||||
LOG_I(RRC,"[UE %d][RAPROC] Frame %d : Logical Channel UL-DCCH (SRB1), Generating RRCConnectionSetupComplete (bytes%d, eNB %d)\n",
|
||||
ctxt_pP->module_id,ctxt_pP->frame, size, eNB_index);
|
||||
LOG_D(RLC,
|
||||
@@ -624,7 +634,8 @@ int rrc_ue_decode_ccch( const protocol_ctxt_t *const ctxt_pP, const SRB_INFO *co
|
||||
rrc_ue_generate_RRCConnectionSetupComplete(
|
||||
ctxt_pP,
|
||||
eNB_index,
|
||||
dl_ccch_msg->message.choice.c1.choice.rrcConnectionSetup.rrc_TransactionIdentifier);
|
||||
dl_ccch_msg->message.choice.c1.choice.rrcConnectionSetup.rrc_TransactionIdentifier,
|
||||
UE_rrc_inst[ctxt_pP->module_id].selected_plmn_identity);
|
||||
rval = 0;
|
||||
break;
|
||||
|
||||
@@ -2794,44 +2805,43 @@ int decode_SIB1( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index,
|
||||
LTE_SystemInformationBlockType1_t *sib1 = UE_rrc_inst[ctxt_pP->module_id].sib1[eNB_index];
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_UE_DECODE_SIB1, VCD_FUNCTION_IN );
|
||||
LOG_I( RRC, "[UE %d] : Dumping SIB 1\n", ctxt_pP->module_id );
|
||||
LTE_PLMN_Identity_t *PLMN_identity = &sib1->cellAccessRelatedInfo.plmn_IdentityList.list.array[0]->plmn_Identity;
|
||||
int mccdigits = PLMN_identity->mcc->list.count;
|
||||
int mncdigits = PLMN_identity->mnc.list.count;
|
||||
int mcc;
|
||||
const int n = sib1->cellAccessRelatedInfo.plmn_IdentityList.list.count;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
LTE_PLMN_Identity_t *PLMN_identity = &sib1->cellAccessRelatedInfo.plmn_IdentityList.list.array[i]->plmn_Identity;
|
||||
int mccdigits = PLMN_identity->mcc->list.count;
|
||||
int mncdigits = PLMN_identity->mnc.list.count;
|
||||
|
||||
if (mccdigits == 2) {
|
||||
mcc = *PLMN_identity->mcc->list.array[0]*10 + *PLMN_identity->mcc->list.array[1];
|
||||
} else {
|
||||
mcc = *PLMN_identity->mcc->list.array[0]*100 + *PLMN_identity->mcc->list.array[1]*10 + *PLMN_identity->mcc->list.array[2];
|
||||
int mcc;
|
||||
if (mccdigits == 2) {
|
||||
mcc = *PLMN_identity->mcc->list.array[0]*10 + *PLMN_identity->mcc->list.array[1];
|
||||
} else {
|
||||
mcc = *PLMN_identity->mcc->list.array[0]*100 + *PLMN_identity->mcc->list.array[1]*10 + *PLMN_identity->mcc->list.array[2];
|
||||
}
|
||||
|
||||
int mnc;
|
||||
if (mncdigits == 2) {
|
||||
mnc = *PLMN_identity->mnc.list.array[0]*10 + *PLMN_identity->mnc.list.array[1];
|
||||
} else {
|
||||
mnc = *PLMN_identity->mnc.list.array[0]*100 + *PLMN_identity->mnc.list.array[1]*10 + *PLMN_identity->mnc.list.array[2];
|
||||
}
|
||||
|
||||
LOG_I( RRC, "PLMN %d MCC %0*d, MNC %0*d\n", i + 1, mccdigits, mcc, mncdigits, mnc);
|
||||
// search internal table for provider name
|
||||
int plmn_ind = 0;
|
||||
|
||||
while (plmn_data[plmn_ind].mcc > 0) {
|
||||
if ((plmn_data[plmn_ind].mcc == mcc) && (plmn_data[plmn_ind].mnc == mnc)) {
|
||||
LOG_I( RRC, "Found %s (name from internal table)\n", plmn_data[plmn_ind].oper_short );
|
||||
break;
|
||||
}
|
||||
|
||||
plmn_ind++;
|
||||
}
|
||||
}
|
||||
|
||||
int mnc;
|
||||
|
||||
if (mncdigits == 2) {
|
||||
mnc = *PLMN_identity->mnc.list.array[0]*10 + *PLMN_identity->mnc.list.array[1];
|
||||
} else {
|
||||
mnc = *PLMN_identity->mnc.list.array[0]*100 + *PLMN_identity->mnc.list.array[1]*10 + *PLMN_identity->mnc.list.array[2];
|
||||
}
|
||||
|
||||
LOG_I( RRC, "PLMN MCC %0*d, MNC %0*d, TAC 0x%04x\n", mccdigits, mcc, mncdigits, mnc,
|
||||
LOG_I( RRC, "TAC 0x%04x\n",
|
||||
((sib1->cellAccessRelatedInfo.trackingAreaCode.size == 2)?((sib1->cellAccessRelatedInfo.trackingAreaCode.buf[0]<<8) + sib1->cellAccessRelatedInfo.trackingAreaCode.buf[1]):0));
|
||||
LOG_I( RRC, "cellReservedForOperatorUse : raw:%ld decoded:%s\n", sib1->cellAccessRelatedInfo.plmn_IdentityList.list.array[0]->cellReservedForOperatorUse,
|
||||
SIBreserved(sib1->cellAccessRelatedInfo.plmn_IdentityList.list.array[0]->cellReservedForOperatorUse) );
|
||||
// search internal table for provider name
|
||||
int plmn_ind = 0;
|
||||
|
||||
while (plmn_data[plmn_ind].mcc > 0) {
|
||||
if ((plmn_data[plmn_ind].mcc == mcc) && (plmn_data[plmn_ind].mnc == mnc)) {
|
||||
LOG_I( RRC, "Found %s (name from internal table)\n", plmn_data[plmn_ind].oper_short );
|
||||
break;
|
||||
}
|
||||
|
||||
plmn_ind++;
|
||||
}
|
||||
|
||||
if (plmn_data[plmn_ind].mcc < 0) {
|
||||
LOG_I( RRC, "Found Unknown operator (no entry in internal table)\n" );
|
||||
}
|
||||
|
||||
LOG_I( RRC, "cellAccessRelatedInfo.cellIdentity : raw:%"PRIu32" decoded:%02x.%02x.%02x.%02x\n",
|
||||
BIT_STRING_to_uint32( &sib1->cellAccessRelatedInfo.cellIdentity ),
|
||||
@@ -2970,6 +2980,7 @@ int decode_SIB1( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index,
|
||||
NAS_CELL_SELECTION_CNF (msg_p).rsrp = rsrp;
|
||||
itti_send_msg_to_task(TASK_NAS_UE, ctxt_pP->instance, msg_p);
|
||||
cell_valid = 1;
|
||||
UE_rrc_inst[ctxt_pP->module_id].selected_plmn_identity = plmn + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2980,7 +2991,11 @@ int decode_SIB1( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index,
|
||||
MessageDef *msg_p;
|
||||
msg_p = itti_alloc_new_message(TASK_RRC_UE, PHY_FIND_NEXT_CELL_REQ);
|
||||
itti_send_msg_to_task(TASK_PHY_UE, ctxt_pP->instance, msg_p);
|
||||
LOG_E(RRC, "Synched with a cell, but PLMN doesn't match our SIM, the message PHY_FIND_NEXT_CELL_REQ is sent but lost in current UE implementation! \n");
|
||||
LOG_E(RRC,
|
||||
"Synched with a cell, but PLMN doesn't match our SIM "
|
||||
"(selected_plmn_identity %d), the message PHY_FIND_NEXT_CELL_REQ "
|
||||
"is sent but lost in current UE implementation!\n",
|
||||
UE_rrc_inst[ctxt_pP->module_id].selected_plmn_identity);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -809,6 +809,7 @@ typedef struct UE_RRC_INST_s {
|
||||
Rrc_Sub_State_t RrcSubState;
|
||||
plmn_t plmnID;
|
||||
Byte_t rat;
|
||||
uint8_t selected_plmn_identity;
|
||||
as_nas_info_t initialNasMsg;
|
||||
OAI_UECapability_t *UECap;
|
||||
uint8_t *UECapability;
|
||||
|
||||
@@ -96,36 +96,34 @@ void extract_imsi(uint8_t *pdu_buf, uint32_t pdu_len, rrc_eNB_ue_context_t *ue_c
|
||||
&& pdu_len > NAS_MESSAGE_SECURITY_HEADER_SIZE))
|
||||
return;
|
||||
|
||||
/* Decode plain NAS message */
|
||||
EMM_msg *e_msg = &nas_msg.plain.emm;
|
||||
emm_msg_header_t *emm_header = &e_msg->header;
|
||||
|
||||
if (header->security_header_type != SECURITY_HEADER_TYPE_NOT_PROTECTED) {
|
||||
/* Decode the message authentication code */
|
||||
DECODE_U32((char *) pdu_buf+size, header->message_authentication_code, size);
|
||||
/* Decode the sequence number */
|
||||
DECODE_U8((char *) pdu_buf+size, header->sequence_number, size);
|
||||
}
|
||||
/* Decode the security header type and the protocol discriminator */
|
||||
DECODE_U8(pdu_buf + size, *(uint8_t *)(emm_header), size);
|
||||
|
||||
/* Note: the value of the pointer (i.e. the address) is given by value, so we
|
||||
* can modify it as we want. The callee retains the original address! */
|
||||
/* Check that this is the right message */
|
||||
if (emm_header->protocol_discriminator != EPS_MOBILITY_MANAGEMENT_MESSAGE)
|
||||
return;
|
||||
}
|
||||
pdu_buf += size;
|
||||
pdu_len -= size;
|
||||
/* Decode plain NAS message */
|
||||
EMM_msg *e_msg = &nas_msg.plain.emm;
|
||||
emm_msg_header_t *emm_header = &e_msg->header;
|
||||
/* First decode the EMM message header */
|
||||
int e_head_size = 0;
|
||||
|
||||
/* Check that buffer contains more than only the header */
|
||||
if (pdu_len <= sizeof(emm_msg_header_t))
|
||||
return;
|
||||
|
||||
/* Decode the security header type and the protocol discriminator */
|
||||
DECODE_U8(pdu_buf + e_head_size, *(uint8_t *)(emm_header), e_head_size);
|
||||
/* First decode the EMM message header */
|
||||
int e_head_size = 0;
|
||||
/* Decode the message type */
|
||||
DECODE_U8(pdu_buf + e_head_size, emm_header->message_type, e_head_size);
|
||||
|
||||
/* Check that this is the right message */
|
||||
if (emm_header->protocol_discriminator != EPS_MOBILITY_MANAGEMENT_MESSAGE)
|
||||
return;
|
||||
|
||||
pdu_buf += e_head_size;
|
||||
pdu_len -= e_head_size;
|
||||
|
||||
|
||||
@@ -825,7 +825,8 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
|
||||
pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup = calloc(1,sizeof(*pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup));
|
||||
NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup;
|
||||
NR_DMRS_UplinkConfig->dmrs_Type = NULL;
|
||||
NR_DMRS_UplinkConfig->dmrs_AdditionalPosition =NR_DMRS_UplinkConfig__dmrs_AdditionalPosition_pos0;
|
||||
NR_DMRS_UplinkConfig->dmrs_AdditionalPosition = calloc(1,sizeof(*NR_DMRS_UplinkConfig->dmrs_AdditionalPosition));
|
||||
*NR_DMRS_UplinkConfig->dmrs_AdditionalPosition = NR_DMRS_UplinkConfig__dmrs_AdditionalPosition_pos0;
|
||||
NR_DMRS_UplinkConfig->phaseTrackingRS=NULL;
|
||||
NR_DMRS_UplinkConfig->maxLength=NULL;
|
||||
NR_DMRS_UplinkConfig->transformPrecodingDisabled = calloc(1,sizeof(*NR_DMRS_UplinkConfig->transformPrecodingDisabled));
|
||||
@@ -1095,7 +1096,19 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
|
||||
|
||||
secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id = calloc(1,sizeof(*secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id));
|
||||
*secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id = 1;
|
||||
secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig = NULL;
|
||||
|
||||
secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig = calloc(1,sizeof(*secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig));
|
||||
NR_PUSCH_ServingCellConfig_t *pusch_scc = calloc(1,sizeof(*pusch_scc));
|
||||
secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig->present = NR_SetupRelease_PUSCH_ServingCellConfig_PR_setup;
|
||||
secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig->choice.setup = pusch_scc;
|
||||
pusch_scc->codeBlockGroupTransmission = NULL;
|
||||
pusch_scc->rateMatching = NULL;
|
||||
pusch_scc->xOverhead = NULL;
|
||||
pusch_scc->ext1=calloc(1,sizeof(*pusch_scc->ext1));
|
||||
pusch_scc->ext1->maxMIMO_Layers = calloc(1,sizeof(*pusch_scc->ext1->maxMIMO_Layers));
|
||||
*pusch_scc->ext1->maxMIMO_Layers = 1;
|
||||
pusch_scc->ext1->processingType2Enabled = NULL;
|
||||
|
||||
secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->carrierSwitching = NULL;
|
||||
|
||||
secondaryCellGroup->spCellConfig->spCellConfigDedicated->supplementaryUplink=NULL;
|
||||
|
||||
@@ -220,8 +220,21 @@ void s1ap_eNB_handle_register_eNB(instance_t instance, s1ap_register_enb_req_t *
|
||||
|
||||
/* Trying to connect to provided list of MME ip address */
|
||||
for (index = 0; index < s1ap_register_eNB->nb_mme; index++) {
|
||||
net_ip_address_t *mme_ip = &s1ap_register_eNB->mme_ip_address[index];
|
||||
struct s1ap_eNB_mme_data_s *mme = NULL;
|
||||
RB_FOREACH(mme, s1ap_mme_map, &new_instance->s1ap_mme_head) {
|
||||
/* Compare whether IPv4 and IPv6 information is already present, in which
|
||||
* wase we do not register again */
|
||||
if (mme->mme_s1_ip.ipv4 == mme_ip->ipv4 && (!mme_ip->ipv4
|
||||
|| strncmp(mme->mme_s1_ip.ipv4_address, mme_ip->ipv4_address, 16) == 0)
|
||||
&& mme->mme_s1_ip.ipv6 == mme_ip->ipv6 && (!mme_ip->ipv6
|
||||
|| strncmp(mme->mme_s1_ip.ipv6_address, mme_ip->ipv6_address, 46) == 0))
|
||||
break;
|
||||
}
|
||||
if (mme)
|
||||
continue;
|
||||
s1ap_eNB_register_mme(new_instance,
|
||||
&s1ap_register_eNB->mme_ip_address[index],
|
||||
mme_ip,
|
||||
&s1ap_register_eNB->enb_ip_address,
|
||||
s1ap_register_eNB->sctp_in_streams,
|
||||
s1ap_register_eNB->sctp_out_streams,
|
||||
|
||||
Reference in New Issue
Block a user