Compare commits

...

12 Commits

Author SHA1 Message Date
Sakthivel Velumani
57c1600dbc Remove UE from slice list(to be squashed)
more fixes: add SRBs to default slice
2024-01-11 22:02:22 +05:30
Sakthivel Velumani
4584c3eb04 Add support for multiple slices per UE 2023-12-18 11:00:06 +05:30
Chieh-Chun Chen
3544c35c7a Fix: correct bytes_last_round to be the instantaneous transmission rate for each slice 2023-12-13 15:33:41 +01:00
Chieh-Chun Chen
b5177eb796 Fix: use min prb ratio as parameter for NVS algo 2023-12-13 14:43:30 +01:00
Chieh-Chun Chen
8eb350c5c8 Add new coming UEs to the corresponding slice if slice exists 2023-12-13 14:43:30 +01:00
Chieh-Chun Chen
d0b00aa53d Fix: save plmn info in RRCSetupComplete 2023-12-13 14:43:30 +01:00
Chieh-Chun Chen
477510cb53 Fix: get the correct nssai in ngap 2023-12-13 14:42:42 +01:00
Chieh-Chun Chen
3c8a95e767 Add slice in RC ran func 2023-12-13 14:42:42 +01:00
Chieh-Chun Chen
f02f3af722 Fixes for NR slicing
- correct return value of slice idx
- add/move UE in UE_list
- use rnti_t instead uint16_t
2023-12-13 14:42:42 +01:00
Chieh-Chun Chen
8f544acf20 Modify the return value of nr_pf_dl to int & remove the unused codes 2023-12-13 14:42:08 +01:00
Chieh-Chun Chen
09a2643518 Fix: correct the teidupf in GTP ran func 2023-12-13 14:42:08 +01:00
Robert Schmidt
2350bf56dd Add 5G preprocessor with NVS slicing 2023-12-13 14:41:53 +01:00
20 changed files with 1331 additions and 57 deletions

View File

@@ -1366,6 +1366,7 @@ set (MAC_NR_SRC
${NR_GNB_MAC_DIR}/mac_rrc_dl_handler.c
${NR_GNB_MAC_DIR}/mac_rrc_ul_direct.c
${NR_GNB_MAC_DIR}/mac_rrc_ul_f1ap.c
${NR_GNB_MAC_DIR}/slicing/nr_slicing.c
)

View File

@@ -44,6 +44,7 @@
#define NR_NB_SC_PER_RB 12
#define NR_MAX_NUM_LCID 32
#define NR_MAX_NUM_QFI 64
#define NR_MAX_NUM_SLICES 10
typedef enum {
nr_FR1 = 0,

View File

@@ -274,7 +274,7 @@ nr_preprocessor_phytest()], multiple users in FR1
2) Checks the quantity of waiting data in RLC
3) Either set up resource allocation directly (e.g., for a single UE,
phytest), or call into a function to perform actual resource allocation.
Currently, this is done using pf_dl() which implements a basic
Currently, this is done using nr_pf_dl() which implements a basic
proportional fair scheduler:
* for every UE, check for retransmission and allocate as necessary
* Calculate the PF coefficient and put eligible UEs into a list

View File

@@ -66,7 +66,7 @@ void read_gtp_sm(void * data)
if (nb_pdu_session > 0) {
int nb_pdu_idx = nb_pdu_session - 1;
gtp->msg.ngut[i].teidgnb = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.gNB_teid_N3;
gtp->msg.ngut[i].teidupf = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.UPF_teid_N3;
gtp->msg.ngut[i].teidupf = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.gtp_teid;
// TODO: one PDU session has multiple QoS Flow
int nb_qos_flow = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.nb_qos;
if (nb_qos_flow > 0) {

View File

@@ -2,8 +2,10 @@ add_library(e2_ran_func_oran STATIC
ran_func_kpm.c
ran_func_rc.c
# For testing purposes
../../flexric/test/rnd/fill_rnd_data_kpm.c
../../flexric/test/rnd/fill_rnd_data_rc.c
../../flexric/test/rnd/fill_rnd_data_kpm.c
../../flexric/test/rnd/fill_rnd_data_rc.c
# For slice
../../../LAYER2/NR_MAC_gNB/slicing/nr_slicing.c
)
target_link_libraries(e2_ran_func_oran PUBLIC asn1_nr_rrc nr_rrc asn1_nr_rrc_hdrs)

View File

@@ -24,6 +24,12 @@
#include "../../flexric/src/sm/rc_sm/ie/ir/lst_ran_param.h"
#include "../../flexric/src/sm/rc_sm/ie/ir/ran_param_list.h"
#include "../../flexric/src/agent/e2_agent_api.h"
#include "common/ran_context.h"
#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h"
#include "openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h"
#include "openair2/LAYER2/NR_MAC_gNB/slicing/nr_slicing.h"
#include "openair2/RRC/NR/rrc_gNB_UE_context.h"
#include "rc_ctrl_service_style_2.h"
#include <assert.h>
#include <stdio.h>
@@ -45,12 +51,306 @@ void read_rc_setup_sm(void* data)
rc->ran_func_def = fill_rc_ran_func_def();
}
static int add_mod_dl_slice(int mod_id,
slice_algorithm_e current_algo,
int id,
uint8_t sst,
uint32_t sd,
char* label,
int64_t pct_reserved)
{
void *params = NULL;
char *slice_algo = NULL;
if (current_algo == NVS_SLICING) {
params = malloc(sizeof(nvs_nr_slice_param_t));
if (!params) return -1;
// use SLICE_SM_NVS_V0_CAPACITY by default
slice_algo = strdup("NVS_CAPACITY");
((nvs_nr_slice_param_t *)params)->type = NVS_RES;
((nvs_nr_slice_param_t *)params)->pct_reserved = pct_reserved/100.0;
} else {
assert(0 != 0 && "Unknow current_algo");
}
nr_pp_impl_param_dl_t *dl = &RC.nrmac[mod_id]->pre_processor_dl;
void *algo = &dl->dl_algo;
char *l = NULL;
if (label)
l = strdup(label);
nssai_t nssai = {.sst = sst, .sd = sd};
LOG_W(NR_MAC, "add DL slice id %d, label %s, slice sched algo %s, pct_reserved %.2f, ue sched algo %s\n", id, l, slice_algo, ((nvs_nr_slice_param_t *)params)->pct_reserved, dl->dl_algo.name);
return dl->addmod_slice(dl->slices, id, nssai, l, algo, params);
}
static void set_new_dl_slice_algo(int mod_id, int algo)
{
gNB_MAC_INST *nrmac = RC.nrmac[mod_id];
assert(nrmac);
nr_pp_impl_param_dl_t dl = nrmac->pre_processor_dl;
switch (algo) {
case NVS_SLICING:
nrmac->pre_processor_dl = nvs_nr_dl_init(mod_id);
break;
default:
nrmac->pre_processor_dl.algorithm = 0;
nrmac->pre_processor_dl = nr_init_fr1_dlsch_preprocessor(0); // assume CC_id = 0
nrmac->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);
}
static int find_dl_slice(nr_slice_info_t *si, uint32_t id)
{
for (int i = 0; i < si->num; ++i) {
if (si->s[i]->id == id)
return i;
}
return -1;
}
static int assoc_ue_to_dl_slice(int mod_id, NR_UE_info_t* assoc_ue, uint32_t assoc_dl_id)
{
nr_pp_impl_param_dl_t *dl = &RC.nrmac[mod_id]->pre_processor_dl;
int new_idx = find_dl_slice(dl->slices, assoc_dl_id);
int old_idx = find_dl_slice(dl->slices, assoc_ue->dl_id);
if (new_idx < 0 || old_idx < 0)
return -100;
LOG_W(NR_MAC, "associate UE RNTI 0x%04x from slice ID %d idx %d to slice ID %d idx %d\n",
assoc_ue->rnti, assoc_ue->dl_id, old_idx, assoc_dl_id, new_idx);
dl->move_UE(dl->slices, assoc_ue, old_idx, new_idx);
return 0;
}
static char* copy_bytearr_to_str(const byte_array_t* ba)
{
if (ba->len < 1)
return NULL;
char* str = calloc(ba->len + 1, sizeof(char));
assert(str != NULL && "memory exhausted\n");
memcpy(str, ba->buf, ba->len);
str[ba->len] = '\0';
return str;
}
static bool nssai_matches(nssai_t a_nssai, uint8_t b_sst, const uint32_t *b_sd)
{
AssertFatal(b_sd == NULL || *b_sd <= 0xffffff, "illegal SD %d\n", *b_sd);
if (b_sd == NULL) {
return a_nssai.sst == b_sst && a_nssai.sd == 0xffffff;
} else {
return a_nssai.sst == b_sst && a_nssai.sd == *b_sd;
}
}
static bool add_mod_rc_slice(int mod_id, size_t slices_len, ran_param_list_t* lst)
{
gNB_MAC_INST *nrmac = RC.nrmac[mod_id];
assert(nrmac);
int current_algo = nrmac->pre_processor_dl.algorithm;
// use NVS algorithm by default
int new_algo = NVS_SLICING;
pthread_mutex_lock(&nrmac->UE_info.mutex);
if (current_algo != new_algo) {
set_new_dl_slice_algo(mod_id, new_algo);
current_algo = new_algo;
if (new_algo > 0)
LOG_D(NR_MAC, "set new algorithm %d\n", current_algo);
else
LOG_W(NR_MAC, "reset slicing algorithm as NONE\n");
}
for (size_t i = 0; i < slices_len; ++i) {
lst_ran_param_t* RRM_Policy_Ratio_Group = &lst->lst_ran_param[i];
//Bug in rc_enc_asn.c:1003, asn didn't define ran_param_id for lst_ran_param_t...
//assert(RRM_Policy_Ratio_Group->ran_param_id == RRM_Policy_Ratio_Group_8_4_3_6 && "wrong RRM_Policy_Ratio_Group id");
assert(RRM_Policy_Ratio_Group->ran_param_struct.sz_ran_param_struct == 4 && "wrong RRM_Policy_Ratio_Group->ran_param_struct.sz_ran_param_struct");
assert(RRM_Policy_Ratio_Group->ran_param_struct.ran_param_struct != NULL && "NULL RRM_Policy_Ratio_Group->ran_param_struct.ran_param_struct");
seq_ran_param_t* RRM_Policy = &RRM_Policy_Ratio_Group->ran_param_struct.ran_param_struct[0];
assert(RRM_Policy->ran_param_id == RRM_Policy_8_4_3_6 && "wrong RRM_Policy id");
assert(RRM_Policy->ran_param_val.type == STRUCTURE_RAN_PARAMETER_VAL_TYPE && "wrong RRM_Policy type");
assert(RRM_Policy->ran_param_val.strct != NULL && "NULL RRM_Policy->ran_param_val.strct");
assert(RRM_Policy->ran_param_val.strct->sz_ran_param_struct == 1 && "wrong RRM_Policy->ran_param_val.strct->sz_ran_param_struct");
assert(RRM_Policy->ran_param_val.strct->ran_param_struct != NULL && "NULL RRM_Policy->ran_param_val.strct->ran_param_struct");
seq_ran_param_t* RRM_Policy_Member_List = &RRM_Policy->ran_param_val.strct->ran_param_struct[0];
assert(RRM_Policy_Member_List->ran_param_id == RRM_Policy_Member_List_8_4_3_6 && "wrong RRM_Policy_Member_List id");
assert(RRM_Policy_Member_List->ran_param_val.type == LIST_RAN_PARAMETER_VAL_TYPE && "wrong RRM_Policy_Member_List type");
assert(RRM_Policy_Member_List->ran_param_val.lst != NULL && "NULL RRM_Policy_Member_List->ran_param_val.lst");
assert(RRM_Policy_Member_List->ran_param_val.lst->sz_lst_ran_param == 1 && "wrong RRM_Policy_Member_List->ran_param_val.lst->sz_lst_ran_param");
assert(RRM_Policy_Member_List->ran_param_val.lst->lst_ran_param != NULL && "NULL RRM_Policy_Member_List->ran_param_val.lst->lst_ran_param");
lst_ran_param_t* RRM_Policy_Member = &RRM_Policy_Member_List->ran_param_val.lst->lst_ran_param[0];
//Bug in rc_enc_asn.c:1003, asn didn't define ran_param_id for lst_ran_param_t ...
//assert(RRM_Policy_Member->ran_param_id == RRM_Policy_Member_8_4_3_6 && "wrong RRM_Policy_Member id");
assert(RRM_Policy_Member->ran_param_struct.sz_ran_param_struct == 2 && "wrong RRM_Policy_Member->ran_param_struct.sz_ran_param_struct");
assert(RRM_Policy_Member->ran_param_struct.ran_param_struct != NULL && "NULL RRM_Policy_Member->ran_param_struct.ran_param_struct");
seq_ran_param_t* PLMN_Identity = &RRM_Policy_Member->ran_param_struct.ran_param_struct[0];
assert(PLMN_Identity->ran_param_id == PLMN_Identity_8_4_3_6 && "wrong PLMN_Identity id");
assert(PLMN_Identity->ran_param_val.type == ELEMENT_KEY_FLAG_FALSE_RAN_PARAMETER_VAL_TYPE && "wrong PLMN_Identity type");
assert(PLMN_Identity->ran_param_val.flag_false != NULL && "NULL PLMN_Identity->ran_param_val.flag_false");
assert(PLMN_Identity->ran_param_val.flag_false->type == OCTET_STRING_RAN_PARAMETER_VALUE && "wrong PLMN_Identity->ran_param_val.flag_false->type");
///// GET RC PLMN ////
char* plmn_str = copy_bytearr_to_str(&PLMN_Identity->ran_param_val.flag_false->octet_str_ran);
int RC_mnc, RC_mcc = 0;
if (strlen(plmn_str) == 6)
sscanf(plmn_str, "%3d%2d", &RC_mcc, &RC_mnc);
else
sscanf(plmn_str, "%3d%3d", &RC_mcc, &RC_mnc);
LOG_D(NR_MAC, "RC PLMN %s, MCC %d, MNC %d\n", plmn_str, RC_mcc, RC_mnc);
free(plmn_str);
seq_ran_param_t* S_NSSAI = &RRM_Policy_Member->ran_param_struct.ran_param_struct[1];
assert(S_NSSAI->ran_param_id == S_NSSAI_8_4_3_6 && "wrong S_NSSAI id");
assert(S_NSSAI->ran_param_val.type == STRUCTURE_RAN_PARAMETER_VAL_TYPE && "wrong S_NSSAI type");
assert(S_NSSAI->ran_param_val.strct != NULL && "NULL S_NSSAI->ran_param_val.strct");
assert(S_NSSAI->ran_param_val.strct->sz_ran_param_struct == 2 && "wrong S_NSSAI->ran_param_val.strct->sz_ran_param_struct");
assert(S_NSSAI->ran_param_val.strct->ran_param_struct != NULL && "NULL S_NSSAI->ran_param_val.strct->ran_param_struct");
seq_ran_param_t* SST = &S_NSSAI->ran_param_val.strct->ran_param_struct[0];
assert(SST->ran_param_id == SST_8_4_3_6 && "wrong SST id");
assert(SST->ran_param_val.type == ELEMENT_KEY_FLAG_FALSE_RAN_PARAMETER_VAL_TYPE && "wrong SST type");
assert(SST->ran_param_val.flag_false != NULL && "NULL SST->ran_param_val.flag_false");
assert(SST->ran_param_val.flag_false->type == OCTET_STRING_RAN_PARAMETER_VALUE && "wrong SST->ran_param_val.flag_false type");
seq_ran_param_t* SD = &S_NSSAI->ran_param_val.strct->ran_param_struct[1];
assert(SD->ran_param_id == SD_8_4_3_6 && "wrong SD id");
assert(SD->ran_param_val.type == ELEMENT_KEY_FLAG_FALSE_RAN_PARAMETER_VAL_TYPE && "wrong SD type");
assert(SD->ran_param_val.flag_false != NULL && "NULL SD->ran_param_val.flag_false");
assert(SD->ran_param_val.flag_false->type == OCTET_STRING_RAN_PARAMETER_VALUE && "wrong SD->ran_param_val.flag_false type");
///// GET RC NSSAI ////
char* rc_sst_str = copy_bytearr_to_str(&SST->ran_param_val.flag_false->octet_str_ran);
uint8_t RC_sst = atoi(rc_sst_str);
char* rc_sd_str = copy_bytearr_to_str(&SD->ran_param_val.flag_false->octet_str_ran);
uint32_t RC_sd = atoi(rc_sd_str);
LOG_D(NR_MAC, "RC (oct) SST %s, SD %s -> (uint) SST %d, SD %d\n", rc_sst_str, rc_sd_str, RC_sst, RC_sd);
///// SLICE LABEL NAME /////
char* sst_str = "SST";
char* sd_str = "SD";
size_t label_nssai_len = strlen(sst_str) + strlen(rc_sst_str) + strlen(sd_str) + strlen(rc_sd_str) + 1;
char* label_nssai = (char*)malloc(label_nssai_len);
assert(label_nssai != NULL && "Memory exhausted");
sprintf(label_nssai, "%s%s%s%s", sst_str, rc_sst_str, sd_str, rc_sd_str);
free(rc_sst_str);
free(rc_sd_str);
///// SLICE NVS CAP /////
seq_ran_param_t* Min_PRB_Policy_Ratio = &RRM_Policy_Ratio_Group->ran_param_struct.ran_param_struct[1];
assert(Min_PRB_Policy_Ratio->ran_param_id == Min_PRB_Policy_Ratio_8_4_3_6 && "wrong Min_PRB_Policy_Ratio id");
assert(Min_PRB_Policy_Ratio->ran_param_val.type == ELEMENT_KEY_FLAG_FALSE_RAN_PARAMETER_VAL_TYPE && "wrong Min_PRB_Policy_Ratio type");
assert(Min_PRB_Policy_Ratio->ran_param_val.flag_false != NULL && "NULL Min_PRB_Policy_Ratio->ran_param_val.flag_false");
assert(Min_PRB_Policy_Ratio->ran_param_val.flag_false->type == INTEGER_RAN_PARAMETER_VALUE && "wrong Min_PRB_Policy_Ratio->ran_param_val.flag_false type");
int64_t nvs_cap = Min_PRB_Policy_Ratio->ran_param_val.flag_false->int_ran;
LOG_I(NR_MAC, "configure slice %ld, label %s, Min_PRB_Policy_Ratio %ld\n", i, label_nssai, nvs_cap);
// TODO: could be extended to support max prb ratio and dedicated prb ratio in the MAC scheduling algorithm
//seq_ran_param_t* Dedicated_PRB_Policy_Ratio = &RRM_Policy_Ratio_Group->ran_param_struct.ran_param_struct[3];
//assert(Dedicated_PRB_Policy_Ratio->ran_param_id == Dedicated_PRB_Policy_Ratio_8_4_3_6 && "wrong Dedicated_PRB_Policy_Ratio id");
//assert(Dedicated_PRB_Policy_Ratio->ran_param_val.type == ELEMENT_KEY_FLAG_FALSE_RAN_PARAMETER_VAL_TYPE && "wrong Dedicated_PRB_Policy_Ratio type");
//assert(Dedicated_PRB_Policy_Ratio->ran_param_val.flag_false != NULL && "NULL Dedicated_PRB_Policy_Ratio->ran_param_val.flag_false");
//assert(Dedicated_PRB_Policy_Ratio->ran_param_val.flag_false->type == INTEGER_RAN_PARAMETER_VALUE && "wrong Dedicated_PRB_Policy_Ratio->ran_param_val.flag_false type");
//int64_t dedicated_prb_ratio = Dedicated_PRB_Policy_Ratio->ran_param_val.flag_false->int_ran;
//LOG_I(NR_MAC, "configure slice %ld, label %s, Dedicated_PRB_Policy_Ratio %ld\n", i, label_nssai, dedicated_prb_ratio);
//seq_ran_param_t* Max_PRB_Policy_Ratio = &RRM_Policy_Ratio_Group->ran_param_struct.ran_param_struct[2];
//assert(Max_PRB_Policy_Ratio->ran_param_id == Max_PRB_Policy_Ratio_8_4_3_6 && "wrong Max_PRB_Policy_Ratio id");
//assert(Max_PRB_Policy_Ratio->ran_param_val.type == ELEMENT_KEY_FLAG_FALSE_RAN_PARAMETER_VAL_TYPE && "wrong Max_PRB_Policy_Ratio type");
//assert(Max_PRB_Policy_Ratio->ran_param_val.flag_false != NULL && "NULL Max_PRB_Policy_Ratio->ran_param_val.flag_false");
//assert(Max_PRB_Policy_Ratio->ran_param_val.flag_false->type == INTEGER_RAN_PARAMETER_VALUE && "wrong Max_PRB_Policy_Ratio->ran_param_val.flag_false type");
//int64_t max_prb_ratio = Max_PRB_Policy_Ratio->ran_param_val.flag_false->int_ran;
//LOG_I(NR_MAC, "configure slice %ld, label %s, Max_PRB_Policy_Ratio %ld\n", i, label_nssai, max_prb_ratio);
///// ADD SLICE /////
const int rc = add_mod_dl_slice(mod_id, current_algo, i, RC_sst, RC_sd, label_nssai, (float)nvs_cap);
free(label_nssai);
if (rc < 0) {
pthread_mutex_unlock(&nrmac->UE_info.mutex);
LOG_E(NR_MAC, "error code %d while updating slices\n", rc);
return false;
}
/// ASSOC SLICE ///
if (nrmac->pre_processor_dl.algorithm <= 0)
LOG_E(NR_MAC, "current slice algo is NONE, no UE can be associated\n");
if (nrmac->UE_info.list[0] == NULL)
LOG_E(NR_MAC, "no UE connected\n");
nr_pp_impl_param_dl_t *dl = &RC.nrmac[mod_id]->pre_processor_dl;
NR_UEs_t *UE_info = &RC.nrmac[mod_id]->UE_info;
UE_iterator(UE_info->list, UE) {
rnti_t rnti = UE->rnti;
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
bool matched_ue = 0;
long lcid = 0;
for (int l = 0; l < sched_ctrl->dl_lc_num; ++l) {
lcid = sched_ctrl->dl_lc_ids[l];
LOG_D(NR_MAC, "l %d, lcid %ld, sst %d, sd %d\n", l, lcid, sched_ctrl->dl_lc_nssai[lcid].sst, sched_ctrl->dl_lc_nssai[lcid].sd);
if (nssai_matches(sched_ctrl->dl_lc_nssai[lcid], RC_sst, &RC_sd)) {
matched_ue = 1; // assume UE only associates to one slice
break;
}
}
if (!matched_ue)
continue;
// TODO: need to fix nssai info in RRCSetupComplete
rrc_gNB_ue_context_t* rrc_ue_context_list = rrc_gNB_get_ue_context_by_rnti_any_du(RC.nrrrc[mod_id], rnti);
uint16_t UE_mcc = rrc_ue_context_list->ue_context.ue_guami.mcc;
uint16_t UE_mnc = rrc_ue_context_list->ue_context.ue_guami.mnc;
uint8_t UE_sst = sched_ctrl->dl_lc_nssai[lcid].sst;
uint32_t UE_sd = sched_ctrl->dl_lc_nssai[lcid].sd;
LOG_D(NR_MAC, "UE: mcc %d mnc %d, sst %d sd %d, RC: mcc %d mnc %d, sst %d sd %d\n",
UE_mcc, UE_mnc, UE_sst, UE_sd, RC_mcc, RC_mnc, RC_sst, RC_sd);
if (UE_mcc == RC_mcc && UE_mnc == RC_mnc && UE_sst == RC_sst && UE_sd == RC_sd) {
/* Check current slice of this RNTI before assoc */
size_t cur_idx = dl->get_UE_slice_idx(dl->slices, rnti);
if (i == cur_idx) {
LOG_D(NR_MAC, "expected DL slice association for UE RNTI 0x%04x\n", rnti);
continue;
}
/* Check this RNTI in the current slice before assoc */
int cur_ue_idx = dl->get_UE_idx(dl->slices->s[cur_idx], rnti);
if (cur_ue_idx < 0) {
LOG_E(NR_MAC, "error while associating RNTI 0x%04x\n", rnti);
continue;
}
/* Associate this RNTI to another dl slice */
int rc = assoc_ue_to_dl_slice(mod_id, nrmac->UE_info.list[cur_ue_idx], i);
if (rc < 0) {
LOG_E(NR_MAC, "error code %d while associating RNTI 0x%04x\n", rc, rnti);
continue;
}
} else {
LOG_W(NR_MAC, "cannot find specified PLMN (mcc %d mnc %d) NSSAI (sst %d sd %d) from the existing UE PLMN (mcc %d mnc %d) NSSAI (sst %d sd %d) \n",
RC_mcc, RC_mnc, RC_sst, RC_sd, UE_mcc, UE_mnc, UE_sst, UE_sd);
}
}
}
pthread_mutex_unlock(&nrmac->UE_info.mutex);
LOG_D(NR_MAC, "All slices add/mod successfully!\n");
return true;
}
sm_ag_if_ans_t write_ctrl_rc_sm(void const* data)
{
assert(data != NULL);
// assert(data->type == RAN_CONTROL_CTRL_V1_03 );
rc_ctrl_req_data_t const* ctrl = (rc_ctrl_req_data_t const*)data;
LOG_I(NR_MAC, "[E2-Agent]: RC CONTROL rx, RIC Style Type %d, Action ID %d\n", ctrl->hdr.frmt_1.ric_style_type, ctrl->hdr.frmt_1.ctrl_act_id);
if(ctrl->hdr.format == FORMAT_1_E2SM_RC_CTRL_HDR){
if(ctrl->hdr.frmt_1.ric_style_type == 1 && ctrl->hdr.frmt_1.ctrl_act_id == 2){
printf("QoS flow mapping configuration \n");
@@ -63,11 +363,11 @@ sm_ag_if_ans_t write_ctrl_rc_sm(void const* data)
} else if(rp[i].ran_param_id == 2){
assert(rp[i].ran_param_val.type == LIST_RAN_PARAMETER_VAL_TYPE);
printf("List of QoS Flows to be modified \n");
for(size_t j = 0; j < ctrl->msg.frmt_1.ran_param[i].ran_param_val.lst->sz_lst_ran_param; ++j){
for(size_t j = 0; j < ctrl->msg.frmt_1.ran_param[i].ran_param_val.lst->sz_lst_ran_param; ++j){
lst_ran_param_t const* lrp = rp[i].ran_param_val.lst->lst_ran_param;
// The following assertion should be true, but there is a bug in the std
// check src/sm/rc_sm/enc/rc_enc_asn.c:1085 and src/sm/rc_sm/enc/rc_enc_asn.c:984
// assert(lrp[j].ran_param_id == 3);
// check src/sm/rc_sm/enc/rc_enc_asn.c:1085 and src/sm/rc_sm/enc/rc_enc_asn.c:984
// assert(lrp[j].ran_param_id == 3);
assert(lrp[j].ran_param_struct.ran_param_struct[0].ran_param_id == 4) ;
assert(lrp[j].ran_param_struct.ran_param_struct[0].ran_param_val.type == ELEMENT_KEY_FLAG_TRUE_RAN_PARAMETER_VAL_TYPE);
@@ -80,7 +380,23 @@ sm_ag_if_ans_t write_ctrl_rc_sm(void const* data)
assert(dir == 0 || dir == 1);
printf("qfi = %ld dir %ld \n", qfi, dir);
}
}
}
}
} else if (ctrl->hdr.frmt_1.ric_style_type == 2 && ctrl->hdr.frmt_1.ctrl_act_id == Slice_level_PRB_quotal_7_6_3_1) {
/// ADD/MOD SLICE ///
e2sm_rc_ctrl_msg_frmt_1_t const* msg = &ctrl->msg.frmt_1;
assert(msg->sz_ran_param == 1 && "not support msg->sz_ran_param != 1");
seq_ran_param_t* RRM_Policy_Ratio_List = &msg->ran_param[0];
assert(RRM_Policy_Ratio_List->ran_param_id == RRM_Policy_Ratio_List_8_4_3_6 && "wrong RRM_Policy_Ratio_List id");
assert(RRM_Policy_Ratio_List->ran_param_val.type == LIST_RAN_PARAMETER_VAL_TYPE && "wrong RRM_Policy_Ratio_List type");
if (RRM_Policy_Ratio_List->ran_param_val.lst) {
size_t slices_len = RRM_Policy_Ratio_List->ran_param_val.lst->sz_lst_ran_param;
const int mod_id = 0;
bool rc = add_mod_rc_slice(mod_id, slices_len, RRM_Policy_Ratio_List->ran_param_val.lst);
if (!rc)
LOG_E(NR_MAC, "failed add/mod slices\n");
} else {
LOG_I(NR_MAC, "RRM_Policy_Ratio_List->ran_param_val.lst is NULL\n");
}
}
}
@@ -90,8 +406,7 @@ sm_ag_if_ans_t write_ctrl_rc_sm(void const* data)
return ans;
}
static
void* emulate_rrc_msg(void* ptr)
static void* emulate_rrc_msg(void* ptr)
{
uint32_t* ric_id = (uint32_t*)ptr;
for(size_t i = 0; i < 5; ++i){
@@ -107,8 +422,7 @@ void* emulate_rrc_msg(void* ptr)
return NULL;
}
static
pthread_t t_ran_ctrl;
static pthread_t t_ran_ctrl;
sm_ag_if_ans_t write_subs_rc_sm(void const* src)
{

View File

@@ -0,0 +1,28 @@
#ifndef OPENAIRINTERFACE_RC_CTRL_SERVICE_STYLE_2_H
#define OPENAIRINTERFACE_RC_CTRL_SERVICE_STYLE_2_H
typedef enum{
DRX_parameter_configuration_7_6_3_1 = 1,
SR_periodicity_configuration_7_6_3_1 = 2,
SPS_parameters_configuration_7_6_3_1 = 3,
Configured_grant_control_7_6_3_1 = 4,
CQI_table_configuration_7_6_3_1 = 5,
Slice_level_PRB_quotal_7_6_3_1 = 6,
} rc_ctrl_service_style_2_act_id_e;
typedef enum {
RRM_Policy_Ratio_List_8_4_3_6 = 1,
RRM_Policy_Ratio_Group_8_4_3_6 = 2,
RRM_Policy_8_4_3_6 = 3,
RRM_Policy_Member_List_8_4_3_6 = 4,
RRM_Policy_Member_8_4_3_6 = 5,
PLMN_Identity_8_4_3_6 = 6,
S_NSSAI_8_4_3_6 = 7,
SST_8_4_3_6 = 8,
SD_8_4_3_6 = 9,
Min_PRB_Policy_Ratio_8_4_3_6 = 10,
Max_PRB_Policy_Ratio_8_4_3_6 = 11,
Dedicated_PRB_Policy_Ratio_8_4_3_6 = 12,
} slice_level_PRB_quota_param_id_e;
#endif // OPENAIRINTERFACE_RC_CTRL_SERVICE_STYLE_2_H

View File

@@ -505,7 +505,7 @@ void nr_mac_config_scc(gNB_MAC_INST *nrmac, NR_ServingCellConfigCommon_t *scc, c
}
if (get_softmodem_params()->phy_test) {
nrmac->pre_processor_dl = nr_preprocessor_phytest;
nrmac->pre_processor_dl.dl = nr_preprocessor_phytest;
nrmac->pre_processor_ul = nr_ul_preprocessor_phytest;
} else {
nrmac->pre_processor_dl = nr_init_fr1_dlsch_preprocessor(0);

View File

@@ -320,8 +320,11 @@ static void nr_store_dlsch_buffer(module_id_t module_id, frame_t frame, sub_fram
{
UE_iterator(RC.nrmac[module_id]->UE_info.list, UE) {
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
sched_ctrl->num_total_bytes = 0;
sched_ctrl->dl_pdus_total = 0;
/* add all LCID to fist slice. This is to have a common post-processor function for both slicing and non-slicing scheduler */
sched_ctrl->last_sched_slice = 0;
sched_ctrl->sliceInfo[sched_ctrl->last_sched_slice].num_total_bytes = 0;
sched_ctrl->sliceInfo[sched_ctrl->last_sched_slice].dl_pdus_total = 0;
reset_nr_list(&sched_ctrl->sliceInfo[sched_ctrl->last_sched_slice].lcid);
/* loop over all activated logical channels */
// Note: DL_SCH_LCID_DCCH, DL_SCH_LCID_DCCH1, DL_SCH_LCID_DTCH
@@ -348,20 +351,22 @@ static void nr_store_dlsch_buffer(module_id_t module_id, frame_t frame, sub_fram
if (sched_ctrl->rlc_status[lcid].bytes_in_buffer == 0)
continue;
sched_ctrl->dl_pdus_total += sched_ctrl->rlc_status[lcid].pdus_in_buffer;
sched_ctrl->num_total_bytes += sched_ctrl->rlc_status[lcid].bytes_in_buffer;
sched_ctrl->sliceInfo[sched_ctrl->last_sched_slice].dl_pdus_total += sched_ctrl->rlc_status[lcid].pdus_in_buffer;
sched_ctrl->sliceInfo[sched_ctrl->last_sched_slice].num_total_bytes += sched_ctrl->rlc_status[lcid].bytes_in_buffer;
add_nr_list(&sched_ctrl->sliceInfo[sched_ctrl->last_sched_slice].lcid, lcid);
LOG_D(MAC,
"[gNB %d][%4d.%2d] %s%d->DLSCH, RLC status for UE %d: %d bytes in buffer, total DL buffer size = %d bytes, %d total PDU bytes, %s TA command\n",
"[gNB %d][%4d.%2d] %s%d->DLSCH, RLC status for UE %d: %d bytes in buffer, total DL buffer size = %d bytes, %d total "
"PDU bytes, %s TA command\n",
module_id,
frame,
slot,
lcid < 4 ? "DCCH":"DTCH",
lcid < 4 ? "DCCH" : "DTCH",
lcid,
UE->rnti,
sched_ctrl->rlc_status[lcid].bytes_in_buffer,
sched_ctrl->num_total_bytes,
sched_ctrl->dl_pdus_total,
sched_ctrl->ta_apply ? "send":"do not send");
sched_ctrl->sliceInfo[sched_ctrl->last_sched_slice].num_total_bytes,
sched_ctrl->sliceInfo[sched_ctrl->last_sched_slice].dl_pdus_total,
sched_ctrl->ta_apply ? "send" : "do not send");
}
}
}
@@ -582,13 +587,30 @@ static int comparator(const void *p, const void *q) {
return ((UEsched_t*)p)->coef < ((UEsched_t*)q)->coef;
}
static void pf_dl(module_id_t module_id,
frame_t frame,
sub_frame_t slot,
NR_UE_info_t **UE_list,
int max_num_ue,
int n_rb_sched,
uint16_t *rballoc_mask)
static void *nr_pf_dl_setup(void)
{
void *data = malloc(MAX_MOBILES_PER_GNB * sizeof(float));
AssertFatal(data, "%s(): could not allocate data\n", __func__);
for (int i = 0; i < MAX_MOBILES_PER_ENB; i++)
*(float *) data = 0.0f;
return data;
}
static void nr_pf_dl_unset(void **data)
{
DevAssert(data);
if (*data)
free(*data);
*data = NULL;
}
static int nr_pf_dl(module_id_t module_id,
frame_t frame,
sub_frame_t slot,
NR_UE_info_t **UE_list,
int max_num_ue,
int n_rb_sched,
uint16_t *rballoc_mask,
void *data)
{
gNB_MAC_INST *mac = RC.nrmac[module_id];
NR_ServingCellConfigCommon_t *scc=mac->common_channels[0].ServingCellConfigCommon;
@@ -649,7 +671,7 @@ static void pf_dl(module_id_t module_id,
}
/* Check DL buffer and skip this UE if no bytes and no TA necessary */
if (sched_ctrl->num_total_bytes == 0 && frame != (sched_ctrl->ta_frame + 10) % 1024)
if (sched_ctrl->sliceInfo[sched_ctrl->last_sched_slice].num_total_bytes == 0 && frame != (sched_ctrl->ta_frame + 10) % 1024)
continue;
/* Calculate coeff */
@@ -796,7 +818,7 @@ static void pf_dl(module_id_t module_id,
sched_pdsch->nrOfLayers,
tda_info->nrOfSymbols,
sched_pdsch->dmrs_parms.N_PRB_DMRS * sched_pdsch->dmrs_parms.N_DMRS_SLOT,
sched_ctrl->num_total_bytes + oh,
sched_ctrl->sliceInfo[sched_ctrl->last_sched_slice].num_total_bytes + oh,
min_rbSize,
max_rbSize,
&TBS,
@@ -813,7 +835,15 @@ static void pf_dl(module_id_t module_id,
remainUEs--;
iterator++;
}
return n_rb_sched;
}
nr_dl_sched_algo_t nr_proportional_fair_wbcqi_dl = {
.name = "nr_proportional_fair_wbcqi_dl",
.setup = nr_pf_dl_setup,
.unset = nr_pf_dl_unset,
.run = nr_pf_dl,
.data = NULL
};
static void nr_fr1_dlsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t slot)
{
@@ -864,16 +894,17 @@ static void nr_fr1_dlsch_preprocessor(module_id_t module_id, frame_t frame, sub_
int max_sched_ues = bw / (average_agg_level * NR_NB_REG_PER_CCE);
/* proportional fair scheduling algorithm */
pf_dl(module_id,
frame,
slot,
UE_info->list,
max_sched_ues,
n_rb_sched,
rballoc_mask);
RC.nrmac[module_id]->pre_processor_dl.dl_algo.run(module_id,
frame,
slot,
UE_info->list,
max_sched_ues,
n_rb_sched,
rballoc_mask,
RC.nrmac[module_id]->pre_processor_dl.dl_algo.data);
}
nr_pp_impl_dl nr_init_fr1_dlsch_preprocessor(int CC_id) {
nr_pp_impl_param_dl_t nr_init_fr1_dlsch_preprocessor(int CC_id) {
/* during initialization: no mutex needed */
/* in the PF algorithm, we have to use the TBsize to compute the coefficient.
* This would include the number of DMRS symbols, which in turn depends on
@@ -898,7 +929,12 @@ nr_pp_impl_dl nr_init_fr1_dlsch_preprocessor(int CC_id) {
}
}
return nr_fr1_dlsch_preprocessor;
nr_pp_impl_param_dl_t impl;
memset(&impl, 0, sizeof(impl));
impl.dl = nr_fr1_dlsch_preprocessor;
impl.dl_algo = nr_proportional_fair_wbcqi_dl;
impl.dl_algo.data = impl.dl_algo.setup();
return impl;
}
void nr_schedule_ue_spec(module_id_t module_id,
@@ -916,7 +952,10 @@ void nr_schedule_ue_spec(module_id_t module_id,
return;
/* PREPROCESSOR */
gNB_mac->pre_processor_dl(module_id, frame, slot);
pthread_mutex_lock(&gNB_mac->UE_info.mutex);
gNB_mac->pre_processor_dl.dl(module_id, frame, slot);
pthread_mutex_unlock(&gNB_mac->UE_info.mutex);
const int CC_id = 0;
NR_ServingCellConfigCommon_t *scc = gNB_mac->common_channels[CC_id].ServingCellConfigCommon;
NR_UEs_t *UE_info = &gNB_mac->UE_info;
@@ -1243,10 +1282,11 @@ void nr_schedule_ue_spec(module_id_t module_id,
start_meas(&gNB_mac->rlc_data_req);
int sdus = 0;
if (sched_ctrl->num_total_bytes > 0) {
/* loop over all activated logical channels */
for (int i = 0; i < sched_ctrl->dl_lc_num; ++i) {
const int lcid = sched_ctrl->dl_lc_ids[i];
if (sched_ctrl->sliceInfo[sched_ctrl->last_sched_slice].num_total_bytes > 0) {
/* loop over all activated logical channels in this slice */
NR_List_Iterator(&sched_ctrl->sliceInfo[sched_ctrl->last_sched_slice].lcid, lcidP)
{
const int lcid = *lcidP;
if (sched_ctrl->rlc_status[lcid].bytes_in_buffer == 0)
continue; // no data for this LC tbs_size_t len = 0;
@@ -1298,6 +1338,7 @@ void nr_schedule_ue_spec(module_id_t module_id,
UE->mac_stats.dl.lc_bytes[lcid] += lcid_bytes;
}
sched_ctrl->harq_slice_map[sched_ctrl->sched_pdsch.dl_harq_pid] = sched_ctrl->last_sched_slice;
} else if (get_softmodem_params()->phy_test || get_softmodem_params()->do_ra) {
/* we will need the large header, phy-test typically allocates all
* resources and fills to the last byte below */

View File

@@ -57,6 +57,7 @@
#define DEBUG_gNB_SCHEDULER 1
#include "common/ran_context.h"
#include "NR_MAC_gNB/slicing/nr_slicing.h"
//#define DEBUG_DCI
@@ -1820,6 +1821,30 @@ void create_nr_list(NR_list_t *list, int len)
list->len = len;
}
/*
* Reset NR_list
*/
void reset_nr_list(NR_list_t *list)
{
list->head = -1;
memset(list->next, -1, list->len);
list->tail = -1;
}
/*
* Check if id is in the list
*/
bool check_nr_list(const NR_list_t *listP, int id)
{
const int *cur = &listP->head;
while (*cur >= 0) {
if (*cur == id)
return true;
cur = &listP->next[*cur];
}
return false;
}
/*
* Resize an NR_list
*/
@@ -1996,6 +2021,10 @@ void delete_nr_ue_data(NR_UE_info_t *UE, NR_COMMON_channels_t *ccPtr, uid_alloca
destroy_nr_list(&sched_ctrl->retrans_ul_harq);
free_sched_pucch_list(sched_ctrl);
uid_linear_allocator_free(uia, UE->uid);
for (int slice = 0; slice < NR_MAX_NUM_SLICES; slice++) {
destroy_nr_list(&sched_ctrl->sliceInfo[slice].lcid);
}
destroy_nr_list(&UE->dl_id);
LOG_I(NR_MAC, "Remove NR rnti 0x%04x\n", UE->rnti);
free(UE);
}
@@ -2358,6 +2387,16 @@ NR_UE_info_t *add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConf
reset_srs_stats(UE);
/* prepare LC list for all slices in this UE */
for (int slice = 0; slice < NR_MAX_NUM_SLICES; slice++) {
create_nr_list(&sched_ctrl->sliceInfo[slice].lcid, NR_MAX_NUM_LCID);
}
create_nr_list(&UE->dl_id, NR_MAX_NUM_SLICES);
// associate UEs to the first slice if slice exists (there is no DRB setup in this stage)
nr_pp_impl_param_dl_t *dl = &RC.nrmac[0]->pre_processor_dl;
if (dl->slices)
dl->add_UE(dl->slices, UE);
NR_SCHED_LOCK(&UE_info->mutex);
int i;
for(i=0; i<MAX_MOBILES_PER_GNB; i++) {
@@ -2506,6 +2545,14 @@ void mac_remove_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rnti)
NR_SCHED_UNLOCK(&UE_info->mutex);
delete_nr_ue_data(UE, nr_mac->common_channels, &UE_info->uid_allocator);
/* Dissociate UE from all corresponding slice*/
nr_pp_impl_param_dl_t *dl = &nr_mac->pre_processor_dl;
if (dl->slices) {
for (int i = 0; i < dl->slices->num; i++) {
dl->remove_UE(dl->slices, UE, i);
}
}
}
uint8_t nr_get_tpc(int target, uint8_t cqi, int incr) {
@@ -2977,6 +3024,17 @@ void prepare_initial_ul_rrc_message(gNB_MAC_INST *mac, NR_UE_info_t *UE)
UE->CellGroup = cellGroupConfig;
process_CellGroup(cellGroupConfig, UE);
/* Assign SRB1 to default slice */
const long lcid = 1;
nr_pp_impl_param_dl_t *dl = &mac->pre_processor_dl;
if (dl->slices) {
nssai_t *default_nssai = &dl->slices->s[0]->nssai;
UE->UE_sched_ctrl.dl_lc_nssai[lcid] = *default_nssai;
LOG_I(NR_MAC, "Setting NSSAI sst: %d, sd: %d for SRB: %ld\n", default_nssai->sst, default_nssai->sd, lcid);
dl->add_UE(dl->slices, UE);
}
/* activate SRB0 */
nr_rlc_activate_srb0(UE->rnti, UE, send_initial_ul_rrc_message);

View File

@@ -76,7 +76,7 @@ void nr_schedule_ue_spec(module_id_t module_id,
nfapi_nr_tx_data_request_t *TX_req);
/* \brief default FR1 DL preprocessor init routine, returns preprocessor to call */
nr_pp_impl_dl nr_init_fr1_dlsch_preprocessor(int CC_id);
nr_pp_impl_param_dl_t nr_init_fr1_dlsch_preprocessor(int CC_id);
void schedule_nr_sib1(module_id_t module_idP,
frame_t frameP,
@@ -181,7 +181,7 @@ int nr_acknack_scheduling(gNB_MAC_INST *mac,
int get_pdsch_to_harq_feedback(NR_PUCCH_Config_t *pucch_Config,
nr_dci_format_t dci_format,
uint8_t *pdsch_to_harq_feedback);
int nr_get_pucch_resource(NR_ControlResourceSet_t *coreset,
NR_PUCCH_Config_t *pucch_Config,
int CCEIndex);
@@ -298,6 +298,8 @@ void remove_nr_list(NR_list_t *listP, int id);
void add_tail_nr_list(NR_list_t *listP, int id);
void add_front_nr_list(NR_list_t *listP, int id);
void remove_front_nr_list(NR_list_t *listP);
void reset_nr_list(NR_list_t *listP);
bool check_nr_list(const NR_list_t *listP, int id);
NR_UE_info_t * find_nr_UE(NR_UEs_t* UEs, rnti_t rntiP);

View File

@@ -26,6 +26,7 @@
#include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h"
#include "openair2/RRC/NR/MESSAGES/asn1_msg.h"
#include "F1AP_CauseRadioNetwork.h"
#include "NR_MAC_gNB/slicing/nr_slicing.h"
#include "uper_decoder.h"
#include "uper_encoder.h"
@@ -237,8 +238,25 @@ static NR_CellGroupConfig_t *clone_CellGroupConfig(const NR_CellGroupConfig_t *o
return cloned;
}
static void set_nssaiConfig(const int drb_len, const f1ap_drb_to_be_setup_t *req_drbs, NR_UE_sched_ctrl_t *sched_ctrl)
static void set_nssaiConfig(const int srb_len,
const f1ap_srb_to_be_setup_t *req_srbs,
const int drb_len,
const f1ap_drb_to_be_setup_t *req_drbs,
NR_UE_sched_ctrl_t *sched_ctrl)
{
gNB_MAC_INST *mac = RC.nrmac[0];
for (int i = 0; i < srb_len; i++) {
const f1ap_srb_to_be_setup_t *srb = &req_srbs[i];
const long lcid = get_lcid_from_srbid(srb->srb_id);
/* consider first slice as default slice and assign it for SRBs */
nr_pp_impl_param_dl_t *dl = &mac->pre_processor_dl;
if (dl->slices) {
nssai_t *default_nssai = &dl->slices->s[0]->nssai;
sched_ctrl->dl_lc_nssai[lcid] = *default_nssai;
LOG_I(NR_MAC, "Setting NSSAI sst: %d, sd: %d for SRB: %ld\n", default_nssai->sst, default_nssai->sd, srb->srb_id);
}
}
for (int i = 0; i < drb_len; i++) {
const f1ap_drb_to_be_setup_t *drb = &req_drbs[i];
@@ -361,8 +379,16 @@ void ue_context_setup_request(const f1ap_ue_context_setup_t *req)
set_QoSConfig(req, &UE->UE_sched_ctrl);
/* Set NSSAI config in MAC for each active DRB */
set_nssaiConfig(req->drbs_to_be_setup_length, req->drbs_to_be_setup, &UE->UE_sched_ctrl);
set_nssaiConfig(req->srbs_to_be_setup_length,
req->srbs_to_be_setup,
req->drbs_to_be_setup_length,
req->drbs_to_be_setup,
&UE->UE_sched_ctrl);
/* Associate UE to the corresponding slice*/
nr_pp_impl_param_dl_t *dl = &mac->pre_processor_dl;
if (dl->slices)
dl->add_UE(dl->slices, UE);
NR_SCHED_UNLOCK(&mac->sched_lock);
/* some sanity checks, since we use the same type for request and response */
@@ -464,7 +490,16 @@ void ue_context_modification_request(const f1ap_ue_context_modif_req_t *req)
set_QoSConfig(req, &UE->UE_sched_ctrl);
/* Set NSSAI config in MAC for each active DRB */
set_nssaiConfig(req->drbs_to_be_setup_length, req->drbs_to_be_setup, &UE->UE_sched_ctrl);
set_nssaiConfig(req->srbs_to_be_setup_length,
req->srbs_to_be_setup,
req->drbs_to_be_setup_length,
req->drbs_to_be_setup,
&UE->UE_sched_ctrl);
/* Associate UE to the corresponding slice*/
nr_pp_impl_param_dl_t *dl = &mac->pre_processor_dl;
if (dl->slices)
dl->add_UE(dl->slices, UE);
} else {
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, new_CellGroup); // we actually don't need it
}

View File

@@ -254,7 +254,7 @@ void mac_top_init_gNB(ngran_node_t node_type,
uid_linear_allocator_init(&RC.nrmac[i]->UE_info.uid_allocator);
if (get_softmodem_params()->phy_test) {
RC.nrmac[i]->pre_processor_dl = nr_preprocessor_phytest;
RC.nrmac[i]->pre_processor_dl.dl = nr_preprocessor_phytest;
RC.nrmac[i]->pre_processor_ul = nr_ul_preprocessor_phytest;
} else {
RC.nrmac[i]->pre_processor_dl = nr_init_fr1_dlsch_preprocessor(0);

View File

@@ -111,6 +111,8 @@ typedef struct {
int len;
} NR_list_t;
#define NR_List_Iterator(BaSe, CuR) for (int *CuR = &(BaSe)->head, *nxt = (BaSe)->next; *CuR >= 0; CuR = &nxt[*CuR])
typedef enum {
RA_IDLE = 0,
Msg2 = 1,
@@ -541,6 +543,14 @@ typedef struct NR_QoS_config_s {
uint64_t priority;
} NR_QoS_config_t;
typedef struct {
/// LCs in this slice
NR_list_t lcid;
/// total amount of data awaiting for this UE
uint32_t num_total_bytes;
uint16_t dl_pdus_total;
} NR_UE_slice_info_t;
/*! \brief scheduling control information set through an API */
#define MAX_CSI_REPORTS 48
typedef struct {
@@ -641,6 +651,13 @@ typedef struct {
nr_srs_feedback_t srs_feedback;
nssai_t dl_lc_nssai[NR_MAX_NUM_LCID];
/// last scheduled slice index
int last_sched_slice;
/// hold information of slices
NR_UE_slice_info_t sliceInfo[NR_MAX_NUM_SLICES];
/// DL harq to slice map
int harq_slice_map[NR_MAX_HARQ_PROCESSES];
// Information about the QoS configuration for each LCID/DRB
NR_QoS_config_t qos_config[NR_MAX_NUM_LCID - 4][NR_MAX_NUM_QFI]; // 0 -CCCH and 1- 3 SRBs(0,1,2)
} NR_UE_sched_ctrl_t;
@@ -714,6 +731,8 @@ typedef struct {
float ul_thr_ue;
float dl_thr_ue;
long pdsch_HARQ_ACK_Codebook;
/// Assoc slice
NR_list_t dl_id;
} NR_UE_info_t;
typedef struct {
@@ -728,6 +747,19 @@ typedef struct {
#define UE_iterator(BaSe, VaR) NR_UE_info_t ** VaR##pptr=BaSe, *VaR; while ((VaR=*(VaR##pptr++)))
/**
* 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, frame_t, sub_frame_t, NR_UE_info_t **, int, int, uint16_t *, void *);
void *data;
} nr_dl_sched_algo_t;
typedef void (*nr_pp_impl_dl)(module_id_t mod_id,
frame_t frame,
sub_frame_t slot);
@@ -735,6 +767,44 @@ typedef bool (*nr_pp_impl_ul)(module_id_t mod_id,
frame_t frame,
sub_frame_t slot);
struct nr_slice_info_s;
struct nr_slice_s;
typedef struct {
int algorithm;
/// inform the slice algorithm about a new UE
void (*add_UE)(struct nr_slice_info_s *s, NR_UE_info_t *new_ue);
/// inform the slice algorithm about a UE that disconnected
void (*remove_UE)(struct nr_slice_info_s *s, NR_UE_info_t* rm_ue, int idx);
/// move a UE to a slice in DL/UL, -1 means don't move (no-op).
void (*move_UE)(struct nr_slice_info_s *s, NR_UE_info_t* assoc_ue, int old_idx, int new_idx);
/// get UE associated slice's index
int (*get_UE_slice_idx)(struct nr_slice_info_s *s, rnti_t rnti);
/// get UE's index from the slice
int (*get_UE_idx)(struct nr_slice_s *si, rnti_t rnti);
/// 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 nr_slice_info_s *s,
int id,
nssai_t nssai,
char *label,
void *sched,
void *slice_params);
/// Returns slice through slice_idx. 1 if successful, 0 if not.
int (*remove_slice)(struct nr_slice_info_s *s, uint8_t slice_idx);
nr_pp_impl_dl dl;
nr_dl_sched_algo_t dl_algo;
void (*destroy)(struct nr_slice_info_s **s);
struct nr_slice_info_s *slices;
} nr_pp_impl_param_dl_t;
typedef struct f1_config_t {
f1ap_setup_req_t *setup_req;
f1ap_setup_resp_t *setup_resp;
@@ -833,7 +903,7 @@ typedef struct gNB_MAC_INST_s {
uint32_t ulsch_max_frame_inactivity;
/// DL preprocessor for differentiated scheduling
nr_pp_impl_dl pre_processor_dl;
nr_pp_impl_param_dl_t pre_processor_dl;
/// UL preprocessor for differentiated scheduling
nr_pp_impl_ul pre_processor_ul;

View File

@@ -0,0 +1,590 @@
/*
* 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 nr_slicing.c
* \brief Generic NR Slicing helper functions and Static Slicing Implementation
* \author Robert Schmidt
* \date 2021
* \email robert.schmidt@eurecom.fr
*/
#define _GNU_SOURCE
#include <stdlib.h>
#include <dlfcn.h>
#include "assertions.h"
#include "common/utils/LOG/log.h"
#include "common/utils/nr/nr_common.h"
#include "openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h"
#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h"
#include "nr_slicing.h"
#include "nr_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 nr_slicing_get_UE_slice_idx(nr_slice_info_t *si, rnti_t rnti)
{
for (int s_len = 0; s_len < si->num; s_len++) {
for (int i = 0; i < MAX_MOBILES_PER_GNB; i++) {
if (si->s[s_len]->UE_list[i] != NULL) {
if (si->s[s_len]->UE_list[i]->rnti == rnti) {
return s_len;
}
}
}
}
LOG_E(NR_MAC, "cannot find slice idx for UE rnti 0x%04x\n", rnti);
return -99;
}
int nr_slicing_get_UE_idx(nr_slice_t *si, rnti_t rnti)
{
for (int i = 0; i < MAX_MOBILES_PER_GNB; i++) {
if (si->UE_list[i] != NULL) {
LOG_D(NR_MAC, "nr_slicing_get_UE_idx: si->UE_list[%d]->rnti %x map to rnti %x\n", i, si->UE_list[i]->rnti, rnti);
if (si->UE_list[i]->rnti == rnti)
return i;
}
}
LOG_E(NR_MAC, "cannot find ue idx for UE rnti 0x%04x\n", rnti);
return -99;
}
static bool nssai_matches(nssai_t a_nssai, uint8_t b_sst, const uint32_t *b_sd)
{
AssertFatal(b_sd == NULL || *b_sd <= 0xffffff, "illegal SD %d\n", *b_sd);
if (b_sd == NULL) {
return a_nssai.sst == b_sst && a_nssai.sd == 0xffffff;
} else {
return a_nssai.sst == b_sst && a_nssai.sd == *b_sd;
}
}
void nr_slicing_add_UE(nr_slice_info_t *si, NR_UE_info_t *new_ue)
{
AssertFatal(si->num > 0 && si->s != NULL, "no slices exists, cannot add UEs\n");
NR_UE_sched_ctrl_t *sched_ctrl = &new_ue->UE_sched_ctrl;
long lcid = 0;
reset_nr_list(&new_ue->dl_id);
for (int i = 0; i < si->num; ++i) {
reset_nr_list(&new_ue->UE_sched_ctrl.sliceInfo[i].lcid);
bool matched_ue = false;
for (int l = 0; l < sched_ctrl->dl_lc_num; ++l) {
lcid = sched_ctrl->dl_lc_ids[l];
LOG_D(NR_MAC, "l %d, lcid %ld, sst %d, sd %d\n", l, lcid, sched_ctrl->dl_lc_nssai[lcid].sst, sched_ctrl->dl_lc_nssai[lcid].sd);
if (nssai_matches(sched_ctrl->dl_lc_nssai[lcid], si->s[i]->nssai.sst, &si->s[i]->nssai.sd)) {
add_nr_list(&new_ue->UE_sched_ctrl.sliceInfo[i].lcid, lcid);
matched_ue = true;
}
}
if (matched_ue) {
add_nr_list(&new_ue->dl_id, si->s[i]->id);
int num_UEs = si->s[i]->num_UEs;
if (si->s[i]->UE_list[num_UEs] == NULL) {
si->s[i]->UE_list[num_UEs] = new_ue;
si->s[i]->num_UEs += 1;
} else {
LOG_E(NR_MAC, "cannot add new UE rnti 0x%04x to slice idx %d, num_UEs %d\n", new_ue->rnti, i, si->s[i]->num_UEs);
}
LOG_W(NR_MAC,
"Add UE rnti 0x%04x to slice idx %d, sst %d, sd %d\n",
new_ue->rnti,
i,
si->s[i]->nssai.sst,
si->s[i]->nssai.sd);
}
}
}
void nr_slicing_remove_UE(nr_slice_info_t *si, NR_UE_info_t* rm_ue, int idx)
{
for (int i = 0; i < MAX_MOBILES_PER_GNB; i++) {
if(si->s[idx]->UE_list[i] != NULL) {
if (si->s[idx]->UE_list[i]->rnti == rm_ue->rnti) {
si->s[idx]->UE_list[i] = NULL;
si->s[idx]->num_UEs -= 1;
remove_nr_list(&rm_ue->dl_id, si->s[idx]->id);
break;
}
}
}
}
void nr_slicing_move_UE(nr_slice_info_t *si, NR_UE_info_t* assoc_ue, int old_idx, int new_idx)
{
DevAssert(new_idx >= -1 && new_idx < si->num);
DevAssert(old_idx >= -1 && old_idx < si->num);
// add UE to new slice
remove_nr_list(&assoc_ue->dl_id, si->s[old_idx]->id);
add_nr_list(&assoc_ue->dl_id, si->s[new_idx]->id);
int cur_idx = si->s[new_idx]->num_UEs;
si->s[new_idx]->UE_list[cur_idx] = assoc_ue;
si->s[new_idx]->num_UEs += 1;
// remove from old slice
for (int i = 0; i < MAX_MOBILES_PER_GNB; i++) {
if(si->s[old_idx]->UE_list[i] != NULL) {
if (si->s[old_idx]->UE_list[i]->rnti == assoc_ue->rnti) {
si->s[old_idx]->UE_list[i] = NULL;
si->s[old_idx]->num_UEs -= 1;
break;
}
}
}
// reorder UE_list
int n, m = 0;
for (n = 0; n < MAX_MOBILES_PER_GNB; n++) {
if (si->s[old_idx]->UE_list[n] != NULL) {
si->s[old_idx]->UE_list[m++] = si->s[old_idx]->UE_list[n];
}
}
while (m < MAX_MOBILES_PER_GNB) {
si->s[old_idx]->UE_list[m++] = NULL;
}
}
int _nr_exists_slice(uint8_t n, nr_slice_t **s, int id)
{
for (int i = 0; i < n; ++i) {
LOG_D(NR_MAC, "_nr_exists_slice(): n %d, s[%d]->id %d, id %d\n", n ,i, s[i]->id, id);
if (s[i]->id == id)
return i;
}
return -1;
}
nr_slice_t *_nr_add_slice(uint8_t *n, nr_slice_t **s)
{
s[*n] = calloc(1, sizeof(nr_slice_t));
if (!s[*n])
return NULL;
*n += 1;
return s[*n - 1];
}
nr_slice_t *_nr_remove_slice(uint8_t *n, nr_slice_t **s, int idx)
{
if (idx >= *n)
return NULL;
nr_slice_t *sr = s[idx];
for (int i = idx + 1; i < *n; ++i)
s[i - 1] = s[i];
*n -= 1;
s[*n] = NULL;
if (sr->label)
free(sr->label);
return sr;
}
/************************* NVS Slicing Implementation **************************/
typedef struct {
float exp; // exponential weight. mov. avg for weight calc
int rb; // number of RBs this slice has been scheduled in last round
float eff; // effective rate for rate slices
float beta_eff; // averaging coeff so we average over roughly one second
int active; // activity state for rate slices
} _nvs_int_t;
int _nvs_nr_admission_control(const nr_slice_info_t *si,
const nvs_nr_slice_param_t *p,
int idx)
{
if (p->type != NVS_RATE && p->type != NVS_RES)
RET_FAIL(-1, "%s(): invalid slice type %d\n", __func__, p->type);
if (p->type == NVS_RATE && p->Mbps_reserved > p->Mbps_reference)
RET_FAIL(-1,
"%s(): a rate slice cannot reserve more than the reference rate\n",
__func__);
if (p->type == NVS_RES && p->pct_reserved > 1.0f)
RET_FAIL(-1, "%s(): cannot reserve more than 1.0\n", __func__);
float sum_req = 0.0f;
for (int i = 0; i < si->num; ++i) {
const nvs_nr_slice_param_t *sp = i == idx ? p : si->s[i]->algo_data;
if (sp->type == NVS_RATE) {
sum_req += sp->Mbps_reserved / sp->Mbps_reference;
} else {
sum_req += sp->pct_reserved;
}
LOG_D(NR_MAC, "slice idx %d, sum_req %.2f\n", i, sum_req);
}
if (idx < 0) { /* not an existing slice */
if (p->type == NVS_RATE)
sum_req += p->Mbps_reserved / p->Mbps_reference;
else
sum_req += p->pct_reserved;
}
LOG_D(NR_MAC, "slice idx %u, pct_reserved %.2f, sum_req %.2f\n", idx, p->pct_reserved, sum_req);
if (sum_req > 1.0)
RET_FAIL(-3,
"%s(): admission control failed: sum of resources is %f > 1.0\n",
__func__, sum_req);
return 0;
}
int addmod_nvs_nr_slice_dl(nr_slice_info_t *si,
int id,
nssai_t nssai,
char *label,
void *algo,
void *slice_params_dl)
{
nvs_nr_slice_param_t *dl = slice_params_dl;
int index = _nr_exists_slice(si->num, si->s, id);
if (index < 0 && si->num >= MAX_NVS_SLICES)
RET_FAIL(-2, "%s(): cannot handle more than %d slices\n", __func__, MAX_NVS_SLICES);
if (index < 0 && !dl)
RET_FAIL(-100, "%s(): no parameters for new slice %d, aborting\n", __func__, id);
if (dl) {
int rc = _nvs_nr_admission_control(si, dl, index);
if (rc < 0)
return rc;
}
nr_slice_t *s = NULL;
if (index >= 0) {
s = si->s[index];
if (label) {
if (s->label) free(s->label);
s->label = label;
}
if (algo && s->dl_algo.run != ((nr_dl_sched_algo_t*)algo)->run) {
s->dl_algo.unset(&s->dl_algo.data);
s->dl_algo = *(nr_dl_sched_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;
} else { /* we have no parameters: we are done */
return index;
}
s->nssai = nssai;
} else {
if (!algo)
RET_FAIL(-14, "%s(): no scheduler algorithm provided\n", __func__);
s = _nr_add_slice(&si->num, si->s);
if (!s)
RET_FAIL(-4, "%s(): cannot allocate memory for slice\n", __func__);
s->int_data = malloc(sizeof(_nvs_int_t));
if (!s->int_data)
RET_FAIL(-5, "%s(): cannot allocate memory for slice internal data\n", __func__);
s->id = id;
s->label = label;
s->dl_algo = *(nr_dl_sched_algo_t*) algo;
if (!s->dl_algo.data)
s->dl_algo.data = s->dl_algo.setup();
s->algo_data = dl;
s->nssai = nssai;
}
_nvs_int_t *nvs_p = s->int_data;
/* reset all slice-internal parameters */
nvs_p->rb = 0;
nvs_p->active = 0;
if (dl->type == NVS_RATE) {
nvs_p->exp = dl->Mbps_reserved / dl->Mbps_reference;
nvs_p->eff = dl->Mbps_reference;
} else {
nvs_p->exp = dl->pct_reserved;
nvs_p->eff = 0; // not used
}
// scale beta so we (roughly) average the eff rate over 1s
nvs_p->beta_eff = BETA / nvs_p->exp;
return index < 0 ? si->num - 1 : index;
}
int remove_nvs_nr_slice_dl(nr_slice_info_t *si, uint8_t slice_idx)
{
if (slice_idx == 0 && si->num <= 1)
return 0;
UE_iterator(si->s[slice_idx]->UE_list, rm_ue) {
nr_slicing_remove_UE(si, rm_ue, slice_idx);
remove_nr_list(&rm_ue->dl_id, si->s[slice_idx]->id);
LOG_D(NR_MAC, "%s(), move UE rnti 0x%04x in slice ID %d idx %d to slice ID %d idx %d\n",
__func__, rm_ue->rnti, si->s[slice_idx]->id, slice_idx, si->s[0]->id, 0);
for (int i = 0; i < MAX_MOBILES_PER_GNB; i++) {
if (si->s[0]->UE_list[i] == NULL) {
si->s[0]->UE_list[i] = rm_ue;
break;
}
}
}
nr_slice_t *sr = _nr_remove_slice(&si->num, si->s, slice_idx);
if (!sr)
return 0;
free(sr->algo_data);
free(sr->int_data);
sr->dl_algo.unset(&sr->dl_algo.data);
free(sr);
return 1;
}
static void nr_store_dlsch_buffer(module_id_t module_id, frame_t frame, sub_frame_t slot)
{
nr_slice_info_t *si = RC.nrmac[module_id]->pre_processor_dl.slices;
for (int s = 0; s < si->num; s++) {
UE_iterator (si->s[s]->UE_list, UE) {
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
sched_ctrl->sliceInfo[s].num_total_bytes = 0;
sched_ctrl->sliceInfo[s].dl_pdus_total = 0;
NR_List_Iterator(&UE->UE_sched_ctrl.sliceInfo[s].lcid, lcidP)
{
const int lcid = *lcidP;
const uint16_t rnti = UE->rnti;
LOG_D(NR_MAC, "In %s: UE %x: LCID %d\n", __FUNCTION__, rnti, lcid);
if (lcid == DL_SCH_LCID_DTCH && sched_ctrl->rrc_processing_timer > 0) {
continue;
}
start_meas(&RC.nrmac[module_id]->rlc_status_ind);
sched_ctrl->rlc_status[lcid] =
mac_rlc_status_ind(module_id, rnti, module_id, frame, slot, ENB_FLAG_YES, MBMS_FLAG_NO, lcid, 0, 0);
stop_meas(&RC.nrmac[module_id]->rlc_status_ind);
if (sched_ctrl->rlc_status[lcid].bytes_in_buffer == 0)
continue;
sched_ctrl->sliceInfo[s].dl_pdus_total += sched_ctrl->rlc_status[lcid].pdus_in_buffer;
sched_ctrl->sliceInfo[s].num_total_bytes += sched_ctrl->rlc_status[lcid].bytes_in_buffer;
LOG_D(MAC,
"[gNB %d][%4d.%2d] %s%d->DLSCH, RLC status for UE %d, slice %d: %d bytes in buffer, total DL buffer size = %d bytes, "
"%d total PDU bytes, %s TA command\n",
module_id,
frame,
slot,
lcid < 4 ? "DCCH" : "DTCH",
lcid,
UE->rnti,
s,
sched_ctrl->rlc_status[lcid].bytes_in_buffer,
sched_ctrl->sliceInfo[s].num_total_bytes,
sched_ctrl->sliceInfo[s].dl_pdus_total,
sched_ctrl->ta_apply ? "send" : "do not send");
}
}
}
}
void nvs_nr_dl(module_id_t mod_id,
frame_t frame,
sub_frame_t slot)
{
gNB_MAC_INST *nrmac = RC.nrmac[mod_id];
NR_UEs_t *UE_info = &nrmac->UE_info;
if (UE_info->list[0] == NULL) /* no UEs at all -> don't bother */
return;
/* check if we are supposed to schedule something */
NR_ServingCellConfigCommon_t *scc = RC.nrmac[mod_id]->common_channels[0].ServingCellConfigCommon;
const int CC_id = 0;
/* Get bwpSize and TDAfrom the first UE */
/* This is temporary and it assumes all UEs have the same BWP and TDA*/
NR_UE_info_t *first_UE=UE_info->list[0];
NR_UE_sched_ctrl_t *sched_ctrl = &first_UE->UE_sched_ctrl;
NR_UE_DL_BWP_t *current_BWP = &first_UE->current_DL_BWP;
const int tda = get_dl_tda(RC.nrmac[mod_id], scc, slot);
int startSymbolIndex, nrOfSymbols;
const int coresetid = sched_ctrl->coreset->controlResourceSetId;
const struct NR_PDSCH_TimeDomainResourceAllocationList *tdaList = get_dl_tdalist(current_BWP, coresetid, sched_ctrl->search_space->searchSpaceType->present, NR_RNTI_C);
AssertFatal(tda < tdaList->list.count, "time_domain_allocation %d>=%d\n", tda, tdaList->list.count);
const int startSymbolAndLength = tdaList->list.array[tda]->startSymbolAndLength;
SLIV2SL(startSymbolAndLength, &startSymbolIndex, &nrOfSymbols);
const uint16_t bwpSize = current_BWP->BWPSize;
const uint16_t BWPStart = current_BWP->BWPStart;
const uint16_t slbitmap = SL_to_bitmap(startSymbolIndex, nrOfSymbols);
uint16_t *vrb_map = RC.nrmac[mod_id]->common_channels[CC_id].vrb_map;
uint16_t rballoc_mask[bwpSize];
int n_rb_sched = 0;
for (int i = 0; i < bwpSize; i++) {
// calculate mask: init with "NOT" vrb_map:
// if any RB in vrb_map is blocked (1), the current RBG will be 0
rballoc_mask[i] = (~vrb_map[i+BWPStart])&0x3fff; //bitwise not and 14 symbols
// if all the pdsch symbols are free
if ((rballoc_mask[i]&slbitmap) == slbitmap) {
n_rb_sched++;
}
}
/* Retrieve amount of data to send */
nr_store_dlsch_buffer(mod_id, frame, slot);
int bw = scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth;
int average_agg_level = 4; // TODO find a better estimation
int max_sched_ues = bw / (average_agg_level * NR_NB_REG_PER_CCE);
nr_slice_info_t *si = RC.nrmac[mod_id]->pre_processor_dl.slices;
int bytes_last_round[MAX_NVS_SLICES] = {0};
for (int s_idx = 0; s_idx < si->num; ++s_idx) {
UE_iterator (si->s[s_idx]->UE_list, UE) {
const NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
bytes_last_round[s_idx] += UE->mac_stats.dl.current_bytes;
/* if UE has data or retransmission, mark respective slice as active */
const int retx_pid = sched_ctrl->retrans_dl_harq.head;
const int retx_slice = sched_ctrl->harq_slice_map[retx_pid];
const bool active = sched_ctrl->sliceInfo[s_idx].num_total_bytes > 0 || retx_slice == s_idx;
((_nvs_int_t *)si->s[s_idx]->int_data)->active |= active;
}
}
float maxw = 0.0f;
int maxidx = -1;
for (int i = 0; i < si->num; ++i) {
nr_slice_t *s = si->s[i];
nvs_nr_slice_param_t *p = s->algo_data;
_nvs_int_t *ip = s->int_data;
float w = 0.0f;
if (p->type == NVS_RATE) {
/* if this slice has been marked as inactive, disable to prevent that
* it's exp rate is uselessly driven down */
if (!ip->active)
continue;
float inst = 0.0f;
if (ip->rb > 0) { /* it was scheduled last round */
/* inst rate: B in last round * 8(bit) / 1000000 (Mbps) * 1000 (1ms) */
inst = (float) bytes_last_round[i] * 8 / 1000;
ip->eff = (1.0f - ip->beta_eff) * ip->eff + ip->beta_eff * inst;
//LOG_W(NR_MAC, "i %d slice %d ip->rb %d inst %f ip->eff %f\n", i, s->id, ip->rb, inst, ip->eff);
ip->rb = 0;
}
ip->exp = (1 - BETA) * ip->exp + BETA * inst;
const float rsv = p->Mbps_reserved * min(1.0f, ip->eff / p->Mbps_reference);
w = rsv / ip->exp;
} else {
float inst = (float)ip->rb / bwpSize;
ip->exp = (1.0f - BETA) * ip->exp + BETA * inst;
w = p->pct_reserved / ip->exp;
}
//LOG_I(NR_MAC, "i %d slice %d type %d ip->exp %f w %f\n", i, s->id, p->type, ip->exp, w);
ip->rb = 0;
if (w > maxw + 0.001f) {
maxw = w;
maxidx = i;
}
}
if (maxidx < 0)
return;
((_nvs_int_t *)si->s[maxidx]->int_data)->rb = n_rb_sched;
UE_iterator (si->s[maxidx]->UE_list, UE) {
UE->UE_sched_ctrl.last_sched_slice = maxidx;
}
/* proportional fair scheduling algorithm */
int rb_rem = si->s[maxidx]->dl_algo.run(mod_id,
frame,
slot,
si->s[maxidx]->UE_list,
max_sched_ues,
n_rb_sched,
rballoc_mask,
si->s[maxidx]->dl_algo.data);
LOG_D(NR_MAC, "%4d.%2d schedule %d RBs at slice idx %d ID %d \n", frame, slot, n_rb_sched - rb_rem, maxidx, si->s[maxidx]->id);
if (rb_rem == n_rb_sched) // if no RBs have been used mark as inactive
((_nvs_int_t *)si->s[maxidx]->int_data)->active = 0;
}
void nvs_nr_destroy(nr_slice_info_t **si)
{
const int n_dl = (*si)->num;
(*si)->num = 0;
for (int i = 0; i < n_dl; ++i) {
nr_slice_t *s = (*si)->s[i];
if (s->label)
free(s->label);
free(s->algo_data);
free(s->int_data);
free(s);
}
free((*si)->s);
}
nr_pp_impl_param_dl_t nvs_nr_dl_init(module_id_t mod_id)
{
nr_slice_info_t *si = calloc(1, sizeof(nr_slice_info_t));
DevAssert(si);
si->num = 0;
si->s = calloc(MAX_NVS_SLICES, sizeof(*si->s));
DevAssert(si->s);
for (int i = 0; i < MAX_MOBILES_PER_GNB; ++i)
si->UE_assoc_slice[i] = -1;
/* insert default slice, all resources */
nvs_nr_slice_param_t *dlp = malloc(sizeof(nvs_nr_slice_param_t));
DevAssert(dlp);
dlp->type = NVS_RES;
dlp->pct_reserved = 1.0f;
nr_dl_sched_algo_t *algo = &RC.nrmac[mod_id]->pre_processor_dl.dl_algo;
algo->data = NULL;
nssai_t nssai = {.sst = 1, .sd = 0};
const int rc = addmod_nvs_nr_slice_dl(si, 0, nssai, strdup("default"), algo, dlp);
DevAssert(0 == rc);
NR_UEs_t *UE_info = &RC.nrmac[mod_id]->UE_info;
UE_iterator(UE_info->list, UE) {
nr_slicing_add_UE(si, UE);
}
nr_pp_impl_param_dl_t nvs;
nvs.algorithm = NVS_SLICING;
nvs.add_UE = nr_slicing_add_UE;
nvs.remove_UE = nr_slicing_remove_UE;
nvs.move_UE = nr_slicing_move_UE;
nvs.get_UE_slice_idx = nr_slicing_get_UE_slice_idx;
nvs.get_UE_idx = nr_slicing_get_UE_idx;
nvs.addmod_slice = addmod_nvs_nr_slice_dl;
nvs.remove_slice = remove_nvs_nr_slice_dl;
nvs.dl = nvs_nr_dl;
// current DL algo becomes default scheduler
nvs.dl_algo = *algo;
nvs.destroy = nvs_nr_destroy;
nvs.slices = si;
return nvs;
}

View File

@@ -0,0 +1,75 @@
/*
* 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 nr_slicing.h
* \brief General NR slice definition and helper parameters
* \author Robert Schmidt
* \date 2021
* \email robert.schmidt@eurecom.fr
*/
#ifndef NR_SLICING_H__
#define NR_SLICING_H__
#include "openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h"
typedef struct nr_slice_s {
/// Arbitrary ID
slice_id_t id;
/// Arbitrary label
char *label;
nr_dl_sched_algo_t dl_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
int num_UEs;
NR_UE_info_t *UE_list[MAX_MOBILES_PER_GNB+1];
nssai_t nssai;
} nr_slice_t;
typedef struct nr_slice_info_s {
uint8_t num;
nr_slice_t **s;
uint8_t UE_assoc_slice[MAX_MOBILES_PER_GNB+1];
} nr_slice_info_t;
#define NVS_SLICING 20
/* arbitrary upper limit, increase if you want to instantiate more slices */
#define MAX_NVS_SLICES NR_MAX_NUM_SLICES
/* window for slice weight averaging -> 1s for fine granularity */
#define BETA 0.001f
typedef struct {
enum nvs_type {NVS_RATE, NVS_RES} type;
union {
struct { float Mbps_reserved; float Mbps_reference; };
struct { float pct_reserved; };
};
} nvs_nr_slice_param_t;
nr_pp_impl_param_dl_t nvs_nr_dl_init(module_id_t mod_id);
#endif /* NR_SLICING_H__ */

View File

@@ -0,0 +1,48 @@
/*
* 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 nr_slicing_internal.h
* \brief Internal NR slice helper functions
* \author Robert Schmidt
* \date 2021
* \email robert.schmidt@eurecom.fr
*/
#ifndef NR_SLICING_INTERNAL_H__
#define NR_SLICING_INTERNAL_H__
#include "nr_slicing.h"
void nr_slicing_add_UE(nr_slice_info_t *si, NR_UE_info_t *new_ue);
void nr_slicing_remove_UE(nr_slice_info_t *si, NR_UE_info_t* rm_ue, int idx);
void nr_slicing_move_UE(nr_slice_info_t *si, NR_UE_info_t* assoc_ue, int old_idx, int new_idx);
int nr_slicing_get_UE_slice_idx(nr_slice_info_t *si, rnti_t rnti);
int nr_slicing_get_UE_idx(nr_slice_t *si, rnti_t rnti);
nr_slice_t *_nr_add_slice(uint8_t *n, nr_slice_t **s);
nr_slice_t *_nr_remove_slice(uint8_t *n, nr_slice_t **s, int idx);
#endif /* NR_SLICING_INTERNAL_H__ */

View File

@@ -1553,6 +1553,12 @@ static int handle_rrcSetupComplete(const protocol_ctxt_t *const ctxt_pP,
}
}
// TODO: need to handle multiple PLMN in RRC Connection Setup Complete
UE->ue_guami.mcc = RC.nrrrc[0]->configuration.mcc[0];
UE->ue_guami.mnc = RC.nrrrc[0]->configuration.mnc[0];
UE->ue_guami.mnc_len = RC.nrrrc[0]->configuration.mnc_digit_length[0];
// LOG_W(NR_RRC, "mcc %d, mnc %d, mnc_len %d\n", UE->ue_guami.mcc, UE->ue_guami.mnc, UE->ue_guami.mnc_len);
rrc_gNB_process_RRCSetupComplete(ctxt_pP, ue_context_p, setup_complete->criticalExtensions.choice.rrcSetupComplete);
LOG_I(NR_RRC, PROTOCOL_NR_RRC_CTXT_UE_FMT " UE State = NR_RRC_CONNECTED \n", PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP));
return 0;

View File

@@ -209,6 +209,9 @@ rrc_gNB_send_NGAP_NAS_FIRST_REQ(
/* selected_plmn_identity: IE is 1-based, convert to 0-based (C array) */
int selected_plmn_identity = rrcSetupComplete->selectedPLMN_Identity - 1;
req->selected_plmn_identity = selected_plmn_identity;
req->ue_identity.guami.mcc = UE->ue_guami.mcc;
req->ue_identity.guami.mnc = UE->ue_guami.mnc;
req->ue_identity.guami.mnc_len = UE->ue_guami.mnc_len;
if (rrcSetupComplete->registeredAMF != NULL) {
NR_RegisteredAMF_t *r_amf = rrcSetupComplete->registeredAMF;

View File

@@ -784,10 +784,12 @@ static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32
OCTET_STRING_TO_INT8(&allow_nssai_item_p->s_NSSAI.sST, msg->allowed_nssai[i].sst);
if(allow_nssai_item_p->s_NSSAI.sD != NULL) {
memcpy(&msg->allowed_nssai[i].sd, allow_nssai_item_p->s_NSSAI.sD, 3);
msg->allowed_nssai[i].sd = 0;
BUFFER_TO_INT24((uint8_t *)allow_nssai_item_p->s_NSSAI.sD->buf, msg->allowed_nssai[i].sd);
} else {
msg->allowed_nssai[i].sd = 0xffffff;
}
NGAP_INFO("Initial Context Request, allowed_nssai ST %d SD 0x%06x\n", msg->allowed_nssai[i].sst, msg->allowed_nssai[i].sd);
}
/* id-UESecurityCapabilities */
@@ -964,13 +966,11 @@ static int ngap_gNB_handle_pdusession_setup_request(sctp_assoc_t assoc_id, uint3
// S-NSSAI
OCTET_STRING_TO_INT8(&item_p->s_NSSAI.sST, msg->pdusession_setup_params[i].nssai.sst);
if (item_p->s_NSSAI.sD != NULL) {
uint8_t *sd_p = (uint8_t *)&msg->pdusession_setup_params[i].nssai.sd;
sd_p[0] = item_p->s_NSSAI.sD->buf[0];
sd_p[1] = item_p->s_NSSAI.sD->buf[1];
sd_p[2] = item_p->s_NSSAI.sD->buf[2];
BUFFER_TO_INT24((uint8_t *)item_p->s_NSSAI.sD->buf, msg->pdusession_setup_params[i].nssai.sd);
} else {
msg->pdusession_setup_params[i].nssai.sd = 0xffffff;
}
NGAP_INFO("Handle Pdusession Setup Request, nssai ST %d SD 0x%06x\n", msg->pdusession_setup_params[i].nssai.sst, msg->pdusession_setup_params[i].nssai.sd);
allocCopy(&msg->pdusession_setup_params[i].nas_pdu, *item_p->pDUSessionNAS_PDU);
allocCopy(&msg->pdusession_setup_params[i].pdusessionTransfer, item_p->pDUSessionResourceSetupRequestTransfer);