mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-15 05:30:29 +00:00
Compare commits
3 Commits
pre-commit
...
add-slice-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d565475939 | ||
|
|
db978a509d | ||
|
|
057f67519f |
@@ -1268,6 +1268,8 @@ set (MAC_NR_SRC
|
||||
${NR_GNB_MAC_DIR}/mac_rrc_ul_direct.c
|
||||
${NR_GNB_MAC_DIR}/mac_rrc_ul_f1ap.c
|
||||
${NR_GNB_MAC_DIR}/nr_radio_config.c
|
||||
${NR_GNB_MAC_DIR}/slicing/nr_slicing_common.c
|
||||
${NR_GNB_MAC_DIR}/slicing/nr_slicing_nvs_rcsm.c
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -49,6 +49,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
|
||||
#define RNTI_NAMES /* see 38.321 Table 7.1-2 RNTI usage */ \
|
||||
R(TYPE_C_RNTI_) /* Cell RNTI */ \
|
||||
R(TYPE_CS_RNTI_) /* Configured Scheduling RNTI */ \
|
||||
|
||||
@@ -280,6 +280,7 @@ void setup_ue_ipv4_route(const char* ifname, int instance_id, const char *ipv4)
|
||||
table_id,
|
||||
ifname,
|
||||
table_id);
|
||||
LOG_D(UTIL, "%s\n", command_line);
|
||||
|
||||
if (res < 0) {
|
||||
LOG_E(UTIL, "Could not create ip rule/route commands string\n");
|
||||
@@ -288,6 +289,11 @@ void setup_ue_ipv4_route(const char* ifname, int instance_id, const char *ipv4)
|
||||
background_system(command_line);
|
||||
}
|
||||
|
||||
static inline bool ue_ifname_exists(const char *ifname)
|
||||
{
|
||||
return if_nametoindex(ifname) != 0;
|
||||
}
|
||||
|
||||
int tun_generate_ifname(char *ifname, const char *ifprefix, int instance_id)
|
||||
{
|
||||
return snprintf(ifname, IFNAMSIZ, "%s%d", ifprefix, instance_id + 1);
|
||||
@@ -299,7 +305,18 @@ int tuntap_generate_ue_ifname(char *ifname, int flag, int instance_id, int pdu_s
|
||||
char pdu_session_string[10];
|
||||
snprintf(pdu_session_string, sizeof(pdu_session_string), "p%d", pdu_session_id);
|
||||
const char *basename = flag == IFF_TUN ? "oaitun_ue" : "oaitap_ue";
|
||||
return snprintf(ifname, IFNAMSIZ, "%s%d%s", basename, instance_id + 1, pdu_session_id == -1 ? "" : pdu_session_string);
|
||||
|
||||
int len = snprintf(ifname, IFNAMSIZ, "%s%d%s", basename, instance_id + 1, pdu_session_id == -1 ? "" : pdu_session_string);
|
||||
assert(len < IFNAMSIZ);
|
||||
int tunid = instance_id + 1;
|
||||
while (ue_ifname_exists(ifname)) {
|
||||
tunid+=1;
|
||||
LOG_W(UTIL, "ifname %s exists, increase ueid suffix to %d\n", ifname, tunid);
|
||||
len = snprintf(ifname, IFNAMSIZ, "%s%d%s", "oaitun_ue", tunid, pdu_session_id == -1 ? "" : pdu_session_string);
|
||||
assert(len < IFNAMSIZ);
|
||||
}
|
||||
LOG_I(UTIL, "%s(), Create ifname %s with ueid %d and pdu_session_id %d, \n", __func__, ifname, tunid, pdu_session_id);
|
||||
return tunid;
|
||||
}
|
||||
|
||||
void tuntap_destroy(const char *dev)
|
||||
|
||||
@@ -75,6 +75,10 @@ add_library(e2_ran_func_du_cucp_cuup STATIC
|
||||
../flexric/test/rnd/fill_rnd_data_slice.c
|
||||
CUSTOMIZED/ran_func_tc.c # currently, not implemented; therefore, filling rnd data
|
||||
../flexric/test/rnd/fill_rnd_data_tc.c
|
||||
|
||||
O-RAN/ran_func_rc_ctrl_slice.c
|
||||
../../LAYER2/NR_MAC_gNB/slicing/nr_slicing_common.c
|
||||
../../LAYER2/NR_MAC_gNB/slicing/nr_slicing_nvs_rcsm.c
|
||||
)
|
||||
|
||||
target_link_libraries(e2_ran_func_du_cucp_cuup PUBLIC asn1_nr_rrc nr_rrc asn1_nr_rrc_hdrs e2_time_obj kpm_ric_info_common_obj 3gpp_derived_ie_obj e2sm_rc_ir_obj sm_common_ie_obj ds sm_common_enc_asn_obj_rc 3gpp_derived_ie_enc_asn_obj_rc)
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "ran_func_rc.h"
|
||||
#include "ran_func_rc_subs.h"
|
||||
#include "ran_func_rc_extern.h"
|
||||
#include "ran_func_rc_ctrl_slice.h"
|
||||
#include "ran_e2sm_ue_id.h"
|
||||
#include "../../flexric/src/sm/rc_sm/ie/ir/lst_ran_param.h"
|
||||
#include "../../flexric/src/sm/rc_sm/ie/ir/ran_param_list.h"
|
||||
@@ -898,41 +899,65 @@ sm_ag_if_ans_t write_ctrl_rc_sm(void const* data)
|
||||
|
||||
assert(ctrl->hdr.format == FORMAT_1_E2SM_RC_CTRL_HDR && "Indication Header Format received not valid");
|
||||
assert(ctrl->msg.format == FORMAT_1_E2SM_RC_CTRL_MSG && "Indication Message Format received not valid");
|
||||
assert(ctrl->hdr.frmt_1.ctrl_act_id == 2 && "Currently only QoS flow mapping configuration supported");
|
||||
|
||||
printf("QoS flow mapping configuration\n");
|
||||
if (ctrl->hdr.frmt_1.ric_style_type == 1 && ctrl->hdr.frmt_1.ctrl_act_id == 2) {
|
||||
printf("QoS flow mapping configuration\n");
|
||||
|
||||
const seq_ran_param_t* ran_param = ctrl->msg.frmt_1.ran_param;
|
||||
const seq_ran_param_t* ran_param = ctrl->msg.frmt_1.ran_param;
|
||||
|
||||
// DRB ID
|
||||
assert(ran_param[0].ran_param_id == 1 && "First RAN Parameter ID has to be DRB ID");
|
||||
assert(ran_param[0].ran_param_val.type == ELEMENT_KEY_FLAG_TRUE_RAN_PARAMETER_VAL_TYPE);
|
||||
printf("DRB ID %ld \n", ran_param[0].ran_param_val.flag_true->int_ran);
|
||||
// DRB ID
|
||||
assert(ran_param[0].ran_param_id == 1 && "First RAN Parameter ID has to be DRB ID");
|
||||
assert(ran_param[0].ran_param_val.type == ELEMENT_KEY_FLAG_TRUE_RAN_PARAMETER_VAL_TYPE);
|
||||
printf("DRB ID %ld \n", ran_param[0].ran_param_val.flag_true->int_ran);
|
||||
|
||||
|
||||
// List of QoS Flows to be modified in DRB
|
||||
assert(ran_param[1].ran_param_id == 2 && "Second RAN Parameter ID has to be List of QoS Flows");
|
||||
assert(ran_param[1].ran_param_val.type == LIST_RAN_PARAMETER_VAL_TYPE);
|
||||
printf("List of QoS Flows to be modified in DRB\n");
|
||||
const lst_ran_param_t* lrp = ran_param[1].ran_param_val.lst->lst_ran_param;
|
||||
// List of QoS Flows to be modified in DRB
|
||||
assert(ran_param[1].ran_param_id == 2 && "Second RAN Parameter ID has to be List of QoS Flows");
|
||||
assert(ran_param[1].ran_param_val.type == LIST_RAN_PARAMETER_VAL_TYPE);
|
||||
printf("List of QoS Flows to be modified in DRB\n");
|
||||
const lst_ran_param_t* lrp = ran_param[1].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->ran_param_struct.ran_param_struct[0].ran_param_id == 3);
|
||||
// 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->ran_param_struct.ran_param_struct[0].ran_param_id == 3);
|
||||
|
||||
// QoS Flow Identifier
|
||||
assert(lrp->ran_param_struct.ran_param_struct[0].ran_param_id == 4);
|
||||
assert(lrp->ran_param_struct.ran_param_struct[0].ran_param_val.type == ELEMENT_KEY_FLAG_TRUE_RAN_PARAMETER_VAL_TYPE);
|
||||
int64_t qfi = lrp->ran_param_struct.ran_param_struct[0].ran_param_val.flag_true->int_ran;
|
||||
assert(qfi > -1 && qfi < 65);
|
||||
// QoS Flow Identifier
|
||||
assert(lrp->ran_param_struct.ran_param_struct[0].ran_param_id == 4);
|
||||
assert(lrp->ran_param_struct.ran_param_struct[0].ran_param_val.type == ELEMENT_KEY_FLAG_TRUE_RAN_PARAMETER_VAL_TYPE);
|
||||
int64_t qfi = lrp->ran_param_struct.ran_param_struct[0].ran_param_val.flag_true->int_ran;
|
||||
assert(qfi > -1 && qfi < 65);
|
||||
|
||||
// QoS Flow Mapping Indication
|
||||
assert(lrp->ran_param_struct.ran_param_struct[1].ran_param_id == 5);
|
||||
assert(lrp->ran_param_struct.ran_param_struct[1].ran_param_val.type == ELEMENT_KEY_FLAG_FALSE_RAN_PARAMETER_VAL_TYPE);
|
||||
int64_t dir = lrp->ran_param_struct.ran_param_struct[1].ran_param_val.flag_false->int_ran;
|
||||
assert(dir == 0 || dir == 1);
|
||||
// QoS Flow Mapping Indication
|
||||
assert(lrp->ran_param_struct.ran_param_struct[1].ran_param_id == 5);
|
||||
assert(lrp->ran_param_struct.ran_param_struct[1].ran_param_val.type == ELEMENT_KEY_FLAG_FALSE_RAN_PARAMETER_VAL_TYPE);
|
||||
int64_t dir = lrp->ran_param_struct.ran_param_struct[1].ran_param_val.flag_false->int_ran;
|
||||
assert(dir == 0 || dir == 1);
|
||||
|
||||
printf("qfi = %ld, dir %ld \n", qfi, dir);
|
||||
printf("qfi = %ld, dir %ld \n", qfi, dir);
|
||||
|
||||
#if defined (NGRAN_GNB_DU)
|
||||
} else if (ctrl->hdr.frmt_1.ric_style_type == 2 && ctrl->hdr.frmt_1.ctrl_act_id == 6) { // Slice_level_PRB_quotal_7_6_3_1 = 6
|
||||
/// 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_E(NR_MAC, "RRM_Policy_Ratio_List->ran_param_val.lst is NULL\n");
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
assert(0!=0 && "unknown ric_style_type and ctrl_act_id\n");
|
||||
}
|
||||
|
||||
|
||||
sm_ag_if_ans_t ans = {.type = CTRL_OUTCOME_SM_AG_IF_ANS_V0};
|
||||
|
||||
367
openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_ctrl_slice.c
Normal file
367
openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_ctrl_slice.c
Normal file
@@ -0,0 +1,367 @@
|
||||
#include "ran_func_rc_ctrl_slice.h"
|
||||
#include "openair2/E2AP/flexric/src/sm/rc_sm/rc_sm_id.h"
|
||||
#include "common/utils/ds/byte_array.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_common.h"
|
||||
#include "openair2/LAYER2/NR_MAC_gNB/slicing/nr_slicing_nvs_rcsm.h"
|
||||
#include "openair2/RRC/NR/rrc_gNB_UE_context.h"
|
||||
#include "openair2/COMMON/f1ap_messages_types.h"
|
||||
#include "openair2/F1AP/f1ap_ids.h"
|
||||
|
||||
typedef struct {
|
||||
uint16_t mcc;
|
||||
uint16_t mnc;
|
||||
} mccmnc_t;
|
||||
|
||||
// 38.413 clause 9.3.3.5
|
||||
static
|
||||
mccmnc_t convert_plmn_to_mccmnc(uint8_t* plmn)
|
||||
{
|
||||
assert(plmn != NULL);
|
||||
|
||||
mccmnc_t res = {0};
|
||||
|
||||
uint8_t mcc1 = plmn[0] & 0x0F; // digit 1
|
||||
uint8_t mcc2 = (plmn[0] >> 4) & 0x0F; // digit 2
|
||||
uint8_t mcc3 = plmn[1] & 0x0F; // digit 3
|
||||
|
||||
res.mcc = mcc1*100 + mcc2*10 + mcc3;
|
||||
|
||||
uint8_t mnc1 = (plmn[1] >> 4 ) & 0x0F; // digit 4
|
||||
uint8_t mnc2 = plmn[2] & 0x0F; // digit 5
|
||||
uint8_t mnc3 = (plmn[2] >> 4) & 0x0F; // digit 6
|
||||
|
||||
if (mnc1 != 0x0f){
|
||||
res.mnc = mnc1*100 + mnc2*10 + mnc3;
|
||||
} else {
|
||||
res.mnc = mnc2*10 + mnc3;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static
|
||||
int add_mod_dl_slice(int mod_id,
|
||||
slice_algorithm_e current_algo,
|
||||
int8_t id,
|
||||
nssai_t nssai,
|
||||
char* label,
|
||||
void *params)
|
||||
{
|
||||
nr_pp_impl_param_dl_t *dl = &RC.nrmac[mod_id]->pre_processor_dl;
|
||||
char *slice_algo = NULL;
|
||||
if (current_algo == NVS_SLICING) {
|
||||
nvs_nr_slice_param_t* nvs_params = (nvs_nr_slice_param_t *)params;
|
||||
if (!nvs_params) return -1;
|
||||
slice_algo = strdup("NVS_SLICING");
|
||||
if (nvs_params->type == NVS_RATE) {
|
||||
LOG_A(NR_MAC, "add/mod DL slice sched algo %s (type: NVS_RATE), Mbps_reserved %.2f, Mbps_reference %.2f, ue sched algo %s\n",
|
||||
slice_algo, nvs_params->Mbps_reserved, nvs_params->Mbps_reference, dl->dl_algo.name);
|
||||
} else if (nvs_params->type == NVS_RES) {
|
||||
LOG_A(NR_MAC, "add/mod DL slice sched algo %s (type: NVS_RES), pct_reserved %.2f, ue sched algo %s\n",
|
||||
slice_algo, nvs_params->pct_reserved, dl->dl_algo.name);
|
||||
} else {
|
||||
assert(0 != 0 && "Unknow nvs_params->type");
|
||||
}
|
||||
|
||||
} else {
|
||||
assert(0 != 0 && "Unknow current_algo, only support PR algo for DL scheduler");
|
||||
}
|
||||
|
||||
void *algo = &dl->dl_algo;
|
||||
char *l = NULL;
|
||||
if (label)
|
||||
l = strdup(label);
|
||||
LOG_A(NR_MAC, "add/mod DL slice id %d, label %s\n", id, l);
|
||||
return dl->addmod_slice(dl->slices, id, nssai, l, algo, (void*) params);
|
||||
}
|
||||
|
||||
static void set_new_dl_slice_algo(int mod_id, int algo)
|
||||
{
|
||||
gNB_MAC_INST *nrmac = RC.nrmac[mod_id];
|
||||
assert(nrmac);
|
||||
NR_SCHED_LOCK(&nrmac->sched_lock);
|
||||
|
||||
nr_pp_impl_param_dl_t dl = nrmac->pre_processor_dl;
|
||||
switch (algo) {
|
||||
case NVS_SLICING:
|
||||
nrmac->pre_processor_dl = nvs_nr_rcsm_dl_init(mod_id);
|
||||
break;
|
||||
default:
|
||||
nrmac->pre_processor_dl.algorithm = 0;
|
||||
nrmac->pre_processor_dl = nr_init_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);
|
||||
NR_SCHED_UNLOCK(&nrmac->sched_lock);
|
||||
}
|
||||
|
||||
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 ngran_node_t get_e2_node_type(void)
|
||||
{
|
||||
ngran_node_t node_type = 0;
|
||||
|
||||
#if defined(NGRAN_GNB_DU) && defined(NGRAN_GNB_CUUP) && defined(NGRAN_GNB_CUCP)
|
||||
node_type = RC.nrrrc[0]->node_type;
|
||||
#elif defined (NGRAN_GNB_CUUP)
|
||||
node_type = ngran_gNB_CUUP;
|
||||
#endif
|
||||
|
||||
return node_type;
|
||||
}
|
||||
|
||||
static
|
||||
mccmnc_t get_ue_mcc_mnc(uint16_t rnti)
|
||||
{
|
||||
mccmnc_t dst = {0};
|
||||
const ngran_node_t node_type = get_e2_node_type();
|
||||
if(node_type == ngran_gNB){
|
||||
rrc_gNB_ue_context_t* rrc_ue_context_list = rrc_gNB_get_ue_context_by_rnti_any_du(RC.nrrrc[0], rnti);
|
||||
dst.mcc = rrc_ue_context_list->ue_context.ue_guami.plmn.mcc;
|
||||
dst.mnc = rrc_ue_context_list->ue_context.ue_guami.plmn.mnc;
|
||||
} else {
|
||||
gNB_MAC_INST const *mac = RC.nrmac[0];
|
||||
f1_config_t const* f1_config = &mac->f1_config;
|
||||
f1ap_setup_req_t const* setup_req = f1_config->setup_req;
|
||||
// Here we suppose that all the cells share the same MCC and MNC
|
||||
// True?
|
||||
f1ap_served_cell_info_t const* info = &setup_req->cell[0].info;
|
||||
|
||||
dst.mcc = info->plmn.mcc;
|
||||
dst.mnc = info->plmn.mnc;
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
static
|
||||
int8_t get_slice_idx_nssai(nr_slice_info_t *slice_info, nssai_t src)
|
||||
{
|
||||
assert(slice_info->num > 0 && "no default slice exists, check init slice function");
|
||||
|
||||
for (size_t i = 0; i < slice_info->num; ++i) {
|
||||
nr_slice_t* s = slice_info->s[i];
|
||||
if (nssai_matches(s->nssai, src.sst, &src.sd)) {
|
||||
LOG_D(NR_MAC, "found existing slice idx %zu, sst %d, sd %d\n", i, s->nssai.sst, s->nssai.sd);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_I(NR_MAC, "not found nssai from existing slices, create a new slice with idx %d, sst %d, sd 0x%06x\n", slice_info->num, src.sst, src.sd);
|
||||
return slice_info->num;
|
||||
}
|
||||
|
||||
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 PR algorithm by default
|
||||
int new_algo = 0;
|
||||
new_algo = NVS_SLICING;
|
||||
|
||||
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 ////
|
||||
mccmnc_t const RC_plmn = convert_plmn_to_mccmnc(PLMN_Identity->ran_param_val.flag_false->octet_str_ran.buf);
|
||||
LOG_D(NR_MAC, "RC PLMN: MCC %u, MNC %u\n", RC_plmn.mcc, RC_plmn.mnc);
|
||||
|
||||
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 ////
|
||||
nssai_t RC_nssai = {0};
|
||||
char* rc_sst_str = cp_ba_to_str(SST->ran_param_val.flag_false->octet_str_ran);
|
||||
RC_nssai.sst = atoi(rc_sst_str);
|
||||
char* rc_sd_str = NULL;
|
||||
if (SD->ran_param_val.flag_false->octet_str_ran.len > 0) {
|
||||
rc_sd_str = cp_ba_to_str(SD->ran_param_val.flag_false->octet_str_ran);
|
||||
RC_nssai.sd = atoi(rc_sd_str);
|
||||
} else {
|
||||
RC_nssai.sd = 0xffffff;
|
||||
}
|
||||
LOG_D(NR_MAC, "RC (oct) SST %s, SD %s -> (uint) SST %d, SD %d\n", rc_sst_str, rc_sd_str, RC_nssai.sst, RC_nssai.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) + (rc_sd_str != NULL ? strlen(rc_sd_str) : 0) + 1;
|
||||
char* label_nssai = malloc(label_nssai_len);
|
||||
assert(label_nssai != NULL && "Memory exhausted");
|
||||
if (rc_sd_str != NULL)
|
||||
sprintf(label_nssai, "%s%s%s%s", sst_str, rc_sst_str, sd_str, rc_sd_str);
|
||||
else
|
||||
sprintf(label_nssai, "%s%s%s%s", sst_str, rc_sst_str, sd_str, "null");
|
||||
free(rc_sst_str);
|
||||
free(rc_sd_str);
|
||||
|
||||
///// SLICE-LEVEL PRB QUOTA /////
|
||||
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 min_prb_ratio = Min_PRB_Policy_Ratio->ran_param_val.flag_false->int_ran;
|
||||
LOG_D(NR_MAC, "configure slice %ld, label %s, Min_PRB_Policy_Ratio %ld\n", i, label_nssai, min_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_D(NR_MAC, "configure slice %ld, label %s, Max_PRB_Policy_Ratio %ld\n", i, label_nssai, max_prb_ratio);
|
||||
|
||||
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_D(NR_MAC, "configure slice %ld, label %s, Dedicated_PRB_Policy_Ratio %ld\n", i, label_nssai, dedicated_prb_ratio);
|
||||
|
||||
void *params = NULL;
|
||||
if (new_algo == NVS_SLICING) {
|
||||
params = malloc(sizeof(nvs_nr_slice_param_t));
|
||||
((nvs_nr_slice_param_t *)params)->type = NVS_RES;
|
||||
((nvs_nr_slice_param_t *)params)->pct_reserved = dedicated_prb_ratio/100.0;
|
||||
//require to convert max/min/dedicated_prb_ratio to Mbps_reserved/reference for NVS_RATE
|
||||
//((nvs_nr_slice_param_t *)params)->type = NVS_RATE;
|
||||
//((nvs_nr_slice_param_t *)params)->Mbps_reserved = //todo
|
||||
//((nvs_nr_slice_param_t *)params)->Mbps_reference = //todo
|
||||
} else {
|
||||
LOG_E(NR_MAC, "unknown slice algo\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
///// ADD DL SLICE /////
|
||||
nr_pp_impl_param_dl_t *dl = &RC.nrmac[mod_id]->pre_processor_dl;
|
||||
int8_t s_id = get_slice_idx_nssai(dl->slices, RC_nssai);
|
||||
NR_SCHED_LOCK(&nrmac->sched_lock);
|
||||
int rc = add_mod_dl_slice(mod_id, current_algo, s_id, RC_nssai, label_nssai, params);
|
||||
NR_SCHED_UNLOCK(&nrmac->sched_lock);
|
||||
if (rc < 0) {
|
||||
LOG_E(NR_MAC, "error code %d while updating DL slices\n", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// ASSOC DL SLICE ///
|
||||
if (nrmac->pre_processor_dl.algorithm <= 0)
|
||||
LOG_W(NR_MAC, "current DL/UL slice algo is NONE, no UE can be associated\n");
|
||||
|
||||
if (nrmac->UE_info.connected_ue_list[0] == NULL)
|
||||
LOG_W(NR_MAC, "no UE connected, no UE can be associated\n");
|
||||
|
||||
|
||||
NR_UEs_t *UE_info = &RC.nrmac[mod_id]->UE_info;
|
||||
UE_iterator(UE_info->connected_ue_list, UE) {
|
||||
rnti_t rnti = UE->rnti;
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
bool assoc_ue = false;
|
||||
for (size_t l = 0; l < seq_arr_size(&sched_ctrl->lc_config); ++l) {
|
||||
const nr_lc_config_t *c = seq_arr_at(&sched_ctrl->lc_config, l);
|
||||
long lcid = c->lcid;
|
||||
LOG_D(NR_MAC, "l %lu, lcid %ld, sst %d, sd %d\n", l, lcid, c->nssai.sst, c->nssai.sd);
|
||||
if (nssai_matches(c->nssai, RC_nssai.sst, &RC_nssai.sd)) {
|
||||
|
||||
mccmnc_t const UE_plmn = get_ue_mcc_mnc(rnti);
|
||||
nssai_t const UE_nssai = c->nssai;
|
||||
LOG_D(NR_MAC, "UE: mcc %u mnc %u, sst %d sd %d, RC: mcc %u mnc %u, sst %d sd %d\n",
|
||||
UE_plmn.mcc, UE_plmn.mnc, UE_nssai.sst, UE_nssai.sd, RC_plmn.mcc, RC_plmn.mnc, RC_nssai.sst, RC_nssai.sd);
|
||||
|
||||
if (UE_plmn.mcc == RC_plmn.mcc && UE_plmn.mnc == RC_plmn.mnc && UE_nssai.sst == RC_nssai.sst && UE_nssai.sd == RC_nssai.sd) {
|
||||
// for one UE has two slices
|
||||
NR_SCHED_LOCK(&nrmac->sched_lock);
|
||||
dl->add_UE(dl->slices, UE);
|
||||
NR_SCHED_UNLOCK(&nrmac->sched_lock);
|
||||
assoc_ue = true;
|
||||
// for one UE has one slice
|
||||
// assoc_ue = assoc_ue_to_slices(dl, s_id, UE);
|
||||
} else {
|
||||
LOG_E(NR_MAC, "Failed adding UE (PLMN: mcc %u mnc %u, NSSAI: sst %d sd %d) to slice (PLMN: mcc %u mnc %u, NSSAI: sst %d sd %d)\n",
|
||||
UE_plmn.mcc, UE_plmn.mnc, UE_nssai.sst, UE_nssai.sd, RC_plmn.mcc, RC_plmn.mnc, RC_nssai.sst, RC_nssai.sd);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!assoc_ue) {
|
||||
LOG_D(NR_MAC, "Failed matching UE rnti %x with current slice (sst %d, sd %d), might lost user plane data\n", rnti, RC_nssai.sst, RC_nssai.sd);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
LOG_D(NR_MAC, "All slices add/mod successfully!\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
33
openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_ctrl_slice.h
Normal file
33
openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_ctrl_slice.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#ifndef RAN_FUNC_RC_CTRL_SLICE_H
|
||||
#define RAN_FUNC_RC_CTRL_SLICE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "openair2/E2AP/flexric/src/sm/rc_sm/ie/ir/lst_ran_param.h"
|
||||
#include "openair2/E2AP/flexric/src/sm/rc_sm/ie/ir/ran_param_list.h"
|
||||
#include "openair2/E2AP/flexric/src/sm/rc_sm/ie/ir/ran_parameter_value.h"
|
||||
#include "openair2/E2AP/flexric/src/sm/rc_sm/ie/ir/ran_parameter_value_type.h"
|
||||
#include "openair2/E2AP/flexric/src/sm/slice_sm/ie/slice_data_ie.h"
|
||||
#include "openair2/E2AP/flexric/src/sm/slice_sm/ie/slice_data_ie.h"
|
||||
#include "openair2/E2AP/flexric/src/lib/sm/ie/ue_id.h"
|
||||
|
||||
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 = 5,
|
||||
RRM_Policy_Member_8_4_3_6 = 6,
|
||||
PLMN_Identity_8_4_3_6 = 7,
|
||||
S_NSSAI_8_4_3_6 = 8,
|
||||
SST_8_4_3_6 = 9,
|
||||
SD_8_4_3_6 = 10,
|
||||
Min_PRB_Policy_Ratio_8_4_3_6 = 11,
|
||||
Max_PRB_Policy_Ratio_8_4_3_6 = 12,
|
||||
Dedicated_PRB_Policy_Ratio_8_4_3_6 = 13,
|
||||
} slice_level_PRB_quota_param_id_e;
|
||||
|
||||
bool add_mod_rc_slice(int mod_id, size_t slices_len, ran_param_list_t* lst);
|
||||
|
||||
|
||||
#endif // RAN_FUNC_RC_CTRL_SLICE_H
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "NR_MAC_gNB/nr_mac_gNB.h"
|
||||
#include "LAYER2/NR_MAC_gNB/mac_proto.h"
|
||||
#include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h"
|
||||
#include "slicing/nr_slicing_common.h"
|
||||
|
||||
/*TAG*/
|
||||
#include "NR_TAG-Id.h"
|
||||
@@ -357,6 +358,50 @@ static uint32_t update_dlsch_buffer(frame_t frame, slot_t slot, NR_UE_info_t *UE
|
||||
return sched_ctrl->num_total_bytes;
|
||||
}
|
||||
|
||||
|
||||
static uint32_t update_dlsch_buffer_per_slices(frame_t frame, slot_t slot, nr_slice_info_t *slices, NR_UE_info_t *UE)
|
||||
{
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
for (int s = 0; s < slices->num; s++) {
|
||||
sched_ctrl->sliceInfoDl[s].num_total_bytes = 0;
|
||||
sched_ctrl->sliceInfoDl[s].dl_pdus_total = 0;
|
||||
|
||||
/* loop over all activated logical channels */
|
||||
for (int i = 0; i < seq_arr_size(&sched_ctrl->sliceInfoDl[s].lc_config); ++i) {
|
||||
const nr_lc_config_t *c = seq_arr_at(&sched_ctrl->sliceInfoDl[s].lc_config, i);
|
||||
const int lcid = c->lcid;
|
||||
const uint16_t rnti = UE->rnti;
|
||||
LOG_D(NR_MAC, "UE %x: LCID %d\n", rnti, lcid);
|
||||
memset(&sched_ctrl->rlc_status[lcid], 0, sizeof(sched_ctrl->rlc_status[lcid]));
|
||||
if (c->suspended)
|
||||
continue;
|
||||
if (lcid == DL_SCH_LCID_DTCH && nr_timer_is_active(&sched_ctrl->transm_interrupt))
|
||||
continue;
|
||||
sched_ctrl->rlc_status[lcid] = nr_mac_rlc_status_ind(rnti, frame, lcid);
|
||||
|
||||
if (sched_ctrl->rlc_status[lcid].bytes_in_buffer == 0)
|
||||
continue;
|
||||
|
||||
// Get the data from the corresponding LCID for the current slice
|
||||
sched_ctrl->sliceInfoDl[s].dl_pdus_total += sched_ctrl->rlc_status[lcid].pdus_in_buffer;
|
||||
sched_ctrl->sliceInfoDl[s].num_total_bytes += sched_ctrl->rlc_status[lcid].bytes_in_buffer;
|
||||
// Record the total bytes across slices
|
||||
sched_ctrl->num_total_bytes += sched_ctrl->sliceInfoDl[s].num_total_bytes;
|
||||
LOG_D(MAC,
|
||||
"%4d.%2d UE %04x LCID %d sliceInfoDl[%d] status: %d bytes, total buffer %d bytes %d PDUs\n",
|
||||
frame,
|
||||
slot,
|
||||
UE->rnti,
|
||||
lcid,
|
||||
s,
|
||||
sched_ctrl->rlc_status[lcid].bytes_in_buffer,
|
||||
sched_ctrl->sliceInfoDl[s].num_total_bytes,
|
||||
sched_ctrl->sliceInfoDl[s].dl_pdus_total);
|
||||
}
|
||||
}
|
||||
return sched_ctrl->num_total_bytes;
|
||||
}
|
||||
|
||||
void finish_nr_dl_harq(NR_UE_sched_ctrl_t *sched_ctrl, int harq_pid)
|
||||
{
|
||||
NR_UE_harq_t *harq = &sched_ctrl->harq_processes[harq_pid];
|
||||
@@ -638,12 +683,29 @@ static int comparator(const void *p, const void *q)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pf_dl(gNB_MAC_INST *mac,
|
||||
post_process_pdsch_t *pp_pdsch,
|
||||
NR_UE_info_t **UE_list,
|
||||
int max_num_ue,
|
||||
int num_beams,
|
||||
int n_rb_sched[num_beams])
|
||||
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_GNB; i++)
|
||||
*(float *) data = 0.0f;
|
||||
return data;
|
||||
}
|
||||
static void nr_pf_dl_unset(void **data)
|
||||
{
|
||||
DevAssert(data);
|
||||
if (*data)
|
||||
free(*data);
|
||||
*data = NULL;
|
||||
}
|
||||
|
||||
static void nr_pf_dl(gNB_MAC_INST *mac,
|
||||
post_process_pdsch_t *pp_pdsch,
|
||||
NR_UE_info_t **UE_list,
|
||||
int max_num_ue,
|
||||
int num_beams,
|
||||
int n_rb_sched[num_beams],
|
||||
void *data)
|
||||
{
|
||||
frame_t frame = pp_pdsch->frame;
|
||||
slot_t slot = pp_pdsch->slot;
|
||||
@@ -715,7 +777,12 @@ static void pf_dl(gNB_MAC_INST *mac,
|
||||
continue;
|
||||
}
|
||||
|
||||
update_dlsch_buffer(pp_pdsch->frame, pp_pdsch->slot, UE);
|
||||
|
||||
if (mac->pre_processor_dl.slices) {
|
||||
update_dlsch_buffer_per_slices(pp_pdsch->frame, pp_pdsch->slot, mac->pre_processor_dl.slices, UE);
|
||||
} else {
|
||||
update_dlsch_buffer(pp_pdsch->frame, pp_pdsch->slot, UE);
|
||||
}
|
||||
|
||||
if (!dlsch_to_schedule(sched_ctrl, frame))
|
||||
continue;
|
||||
@@ -823,7 +890,7 @@ static void pf_dl(gNB_MAC_INST *mac,
|
||||
|
||||
uint16_t max_rbSize = 1;
|
||||
|
||||
while (rbStart + max_rbSize <= rbStop && !(rballoc_mask[rbStart + max_rbSize + bwp_start] & slbitmap))
|
||||
while (rbStart + max_rbSize <= rbStop && !(rballoc_mask[rbStart + max_rbSize + bwp_start] & slbitmap) && max_rbSize < n_rb_sched[beam.idx])
|
||||
max_rbSize++;
|
||||
|
||||
if (max_rbSize < min_rbSize) {
|
||||
@@ -906,13 +973,20 @@ static void pf_dl(gNB_MAC_INST *mac,
|
||||
// PDUs, we replace with 3 * numPDUs
|
||||
const int oh = 3 * 4 + (sched_ctrl->ta_apply ? 2 : 0);
|
||||
//const int oh = 3 * sched_ctrl->dl_pdus_total + (sched_ctrl->ta_apply ? 2 : 0);
|
||||
int32_t num_total_bytes = 0;
|
||||
if (mac->pre_processor_dl.slices) {
|
||||
num_total_bytes = sched_ctrl->sliceInfoDl[sched_ctrl->sched_dl_idx].num_total_bytes;
|
||||
LOG_D(NR_MAC, "sched_ctrl->sched_dl_idx %d, num_total_bytes %d\n", sched_ctrl->sched_dl_idx, sched_ctrl->sliceInfoDl[sched_ctrl->sched_dl_idx].num_total_bytes);
|
||||
} else {
|
||||
num_total_bytes = sched_ctrl->num_total_bytes;
|
||||
}
|
||||
nr_find_nb_rb(sched_pdsch.Qm,
|
||||
sched_pdsch.R,
|
||||
1, // no transform precoding for DL
|
||||
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,
|
||||
num_total_bytes + oh,
|
||||
min_rbSize,
|
||||
max_rbSize,
|
||||
&sched_pdsch.tb_size,
|
||||
@@ -923,6 +997,9 @@ static void pf_dl(gNB_MAC_INST *mac,
|
||||
/* transmissions: directly allocate */
|
||||
n_rb_sched[beam.idx] -= sched_pdsch.rbSize;
|
||||
|
||||
LOG_D(NR_MAC, "%d.%d PF schedule %d RBs to UE rnti %x, still have %d RBs\n",
|
||||
frame, slot, sched_pdsch.rbSize, rnti, n_rb_sched[beam.idx]);
|
||||
|
||||
for (int rb = bwp_start; rb < sched_pdsch.rbSize; rb++)
|
||||
rballoc_mask[rb + sched_pdsch.rbStart] |= slbitmap;
|
||||
|
||||
@@ -931,6 +1008,14 @@ static void pf_dl(gNB_MAC_INST *mac,
|
||||
}
|
||||
}
|
||||
|
||||
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_dlsch_preprocessor(gNB_MAC_INST *mac, post_process_pdsch_t *pp_pdsch)
|
||||
{
|
||||
NR_UEs_t *UE_info = &mac->UE_info;
|
||||
@@ -952,12 +1037,23 @@ static void nr_dlsch_preprocessor(gNB_MAC_INST *mac, post_process_pdsch_t *pp_pd
|
||||
max_sched_ues = min(max_sched_ues, MAX_DCI_CORESET);
|
||||
|
||||
/* proportional fair scheduling algorithm */
|
||||
pf_dl(mac, pp_pdsch, UE_info->connected_ue_list, max_sched_ues, num_beams, n_rb_sched);
|
||||
mac->pre_processor_dl.dl_algo.run(mac,
|
||||
pp_pdsch,
|
||||
UE_info->connected_ue_list,
|
||||
max_sched_ues,
|
||||
num_beams,
|
||||
n_rb_sched,
|
||||
mac->pre_processor_dl.dl_algo.data);
|
||||
}
|
||||
|
||||
nr_pp_impl_dl nr_init_dlsch_preprocessor(int CC_id)
|
||||
nr_pp_impl_param_dl_t nr_init_dlsch_preprocessor(int CC_id)
|
||||
{
|
||||
return nr_dlsch_preprocessor;
|
||||
nr_pp_impl_param_dl_t impl;
|
||||
memset(&impl, 0, sizeof(impl));
|
||||
impl.dl = nr_dlsch_preprocessor;
|
||||
impl.dl_algo = nr_proportional_fair_wbcqi_dl;
|
||||
impl.dl_algo.data = impl.dl_algo.setup();
|
||||
return impl;
|
||||
}
|
||||
|
||||
nfapi_nr_dl_tti_pdsch_pdu_rel15_t *prepare_pdsch_pdu(nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdsch_pdu,
|
||||
@@ -1280,7 +1376,7 @@ void post_process_dlsch(gNB_MAC_INST *nr_mac, post_process_pdsch_t *pdsch, NR_UE
|
||||
start_meas(&nr_mac->rlc_data_req);
|
||||
int sdus = 0;
|
||||
|
||||
if (sched_ctrl->num_total_bytes > 0) {
|
||||
if (!nr_mac->pre_processor_dl.slices && sched_ctrl->num_total_bytes > 0) {
|
||||
/* loop over all activated logical channels */
|
||||
for (int i = 0; i < seq_arr_size(&sched_ctrl->lc_config); ++i) {
|
||||
const nr_lc_config_t *c = seq_arr_at(&sched_ctrl->lc_config, i);
|
||||
@@ -1330,6 +1426,58 @@ void post_process_dlsch(gNB_MAC_INST *nr_mac, post_process_pdsch_t *pdsch, NR_UE
|
||||
sdus += 1;
|
||||
}
|
||||
|
||||
UE->mac_stats.dl.lc_bytes[lcid] += lcid_bytes;
|
||||
}
|
||||
} else if (nr_mac->pre_processor_dl.slices && sched_ctrl->sliceInfoDl[sched_ctrl->sched_dl_idx].num_total_bytes > 0) {
|
||||
/* loop over all activated logical channels */
|
||||
for (int i = 0; i < seq_arr_size(&sched_ctrl->sliceInfoDl[sched_ctrl->sched_dl_idx].lc_config); ++i) {
|
||||
const nr_lc_config_t *c = seq_arr_at(&sched_ctrl->sliceInfoDl[sched_ctrl->sched_dl_idx].lc_config, i);
|
||||
const int lcid = c->lcid;
|
||||
|
||||
if (sched_ctrl->rlc_status[lcid].bytes_in_buffer == 0)
|
||||
continue; // no data for this LC tbs_size_t len = 0;
|
||||
|
||||
int lcid_bytes=0;
|
||||
while (bufEnd-buf > sizeof(NR_MAC_SUBHEADER_LONG) + 1 ) {
|
||||
// we do not know how much data we will get from RLC, i.e., whether it
|
||||
// will be longer than 256B or not. Therefore, reserve space for long header, then
|
||||
// fetch data, then fill real length
|
||||
NR_MAC_SUBHEADER_LONG *header = (NR_MAC_SUBHEADER_LONG *) buf;
|
||||
/* limit requested number of bytes to what preprocessor specified, or
|
||||
* such that TBS is full */
|
||||
const rlc_buffer_occupancy_t ndata = min(sched_ctrl->rlc_status[lcid].bytes_in_buffer,
|
||||
bufEnd-buf-sizeof(NR_MAC_SUBHEADER_LONG));
|
||||
tbs_size_t len = nr_mac_rlc_data_req(module_id,
|
||||
rnti,
|
||||
true,
|
||||
lcid,
|
||||
ndata,
|
||||
(char *)buf+sizeof(NR_MAC_SUBHEADER_LONG));
|
||||
LOG_D(NR_MAC,
|
||||
"%4d.%2d RNTI %04x: %d bytes from %s %d (ndata %d, remaining size %ld)\n",
|
||||
frame,
|
||||
slot,
|
||||
rnti,
|
||||
len,
|
||||
lcid < 4 ? "DCCH" : "DTCH",
|
||||
lcid,
|
||||
ndata,
|
||||
bufEnd-buf-sizeof(NR_MAC_SUBHEADER_LONG));
|
||||
|
||||
if (len == 0)
|
||||
break;
|
||||
|
||||
T(T_GNB_MAC_LCID_DL, T_INT(rnti), T_INT(frame), T_INT(slot), T_INT(lcid), T_INT(len * 8), T_INT(nr_rlc_tx_list_occupancy(rnti, lcid)));
|
||||
header->R = 0;
|
||||
header->F = 1;
|
||||
header->LCID = lcid;
|
||||
header->L = htons(len);
|
||||
buf += len+sizeof(NR_MAC_SUBHEADER_LONG);
|
||||
dlsch_total_bytes += len;
|
||||
lcid_bytes += len;
|
||||
sdus += 1;
|
||||
}
|
||||
|
||||
UE->mac_stats.dl.lc_bytes[lcid] += lcid_bytes;
|
||||
}
|
||||
} else if (get_softmodem_params()->phy_test || get_softmodem_params()->do_ra) {
|
||||
@@ -1444,5 +1592,5 @@ void nr_schedule_ue_spec(module_id_t module_id,
|
||||
post_process_pdsch_t pdsch = { frame, slot, dl_req, TX_req };
|
||||
|
||||
/* PREPROCESSOR */
|
||||
gNB_mac->pre_processor_dl(gNB_mac, &pdsch);
|
||||
gNB_mac->pre_processor_dl.dl(gNB_mac, &pdsch);
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
|
||||
#include "common/ran_context.h"
|
||||
#include "nfapi/oai_integration/vendor_ext.h"
|
||||
#include "NR_MAC_gNB/slicing/nr_slicing_common.h"
|
||||
|
||||
#include "common/utils/alg/find.h"
|
||||
|
||||
@@ -2358,6 +2359,32 @@ 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;
|
||||
for(int i = 0; i < list->len; ++i){
|
||||
list->next[i] = -1;
|
||||
}
|
||||
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
|
||||
*/
|
||||
@@ -2410,8 +2437,10 @@ void add_nr_list(NR_list_t *listP, int id)
|
||||
cur = &listP->next[*cur];
|
||||
}
|
||||
*cur = id;
|
||||
if (listP->next[id] < 0)
|
||||
if (listP->next[id] < 0) {
|
||||
listP->next[id] = -1;
|
||||
listP->tail = id;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2509,6 +2538,11 @@ void delete_nr_ue_data(NR_UE_info_t *UE, NR_COMMON_channels_t *ccPtr, uid_alloca
|
||||
free_transportBlock_buffer(&sched_ctrl->harq_processes[i].transportBlock);
|
||||
free_sched_pucch_list(sched_ctrl);
|
||||
uid_linear_allocator_free(uia, UE->uid);
|
||||
for (int slice = 0; slice < NR_MAX_NUM_SLICES; slice++) {
|
||||
seq_arr_free(&sched_ctrl->sliceInfoDl[slice].lc_config, NULL);
|
||||
}
|
||||
// Dissociate UE from all corresponding slice
|
||||
destroy_nr_list(&UE->dl_id);
|
||||
LOG_I(NR_MAC, "Remove NR rnti 0x%04x\n", UE->rnti);
|
||||
free_and_zero(UE->ra);
|
||||
free(UE);
|
||||
@@ -2988,6 +3022,10 @@ NR_UE_info_t *get_new_nr_ue_inst(uid_allocator_t *uia, rnti_t rnti, NR_CellGroup
|
||||
|
||||
// initialize LCID structure
|
||||
seq_arr_init(&sched_ctrl->lc_config, sizeof(nr_lc_config_t));
|
||||
for (int slice = 0; slice < NR_MAX_NUM_SLICES; slice++) {
|
||||
seq_arr_init(&sched_ctrl->sliceInfoDl[slice].lc_config, sizeof(nr_lc_config_t));
|
||||
}
|
||||
create_nr_list(&UE->dl_id, NR_MAX_NUM_SLICES);
|
||||
return UE;
|
||||
}
|
||||
|
||||
@@ -3115,6 +3153,12 @@ void mac_remove_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rnti)
|
||||
NR_SCHED_ENSURE_LOCKED(&nr_mac->sched_lock);
|
||||
NR_UEs_t *UE_info = &nr_mac->UE_info;
|
||||
NR_UE_info_t *UE = remove_UE_from_list(MAX_MOBILES_PER_GNB + 1, UE_info->connected_ue_list, rnti);
|
||||
// Remove the UE from the slice->UE_list
|
||||
nr_pp_impl_param_dl_t *dl = &nr_mac->pre_processor_dl;
|
||||
if (dl->slices) {
|
||||
for (int s = 0; s < dl->slices->num; s++)
|
||||
dl->remove_UE(dl->slices, UE, s);
|
||||
}
|
||||
if (UE)
|
||||
delete_nr_ue_data(UE, nr_mac->common_channels, &UE_info->uid_allocator);
|
||||
else
|
||||
@@ -3852,8 +3896,25 @@ bool prepare_initial_ul_rrc_message(gNB_MAC_INST *mac, NR_UE_info_t *UE)
|
||||
DevAssert(bearer->servedRadioBearer->choice.srb_Identity == srb_id);
|
||||
nr_rlc_add_srb(UE->rnti, bearer->servedRadioBearer->choice.srb_Identity, bearer);
|
||||
int priority = bearer->mac_LogicalChannelConfig->ul_SpecificParameters->priority;
|
||||
nr_lc_config_t c = {.lcid = bearer->logicalChannelIdentity, .priority = priority};
|
||||
nssai_t default_nssai = {.sst = 0, .sd = 0};
|
||||
nr_lc_config_t c = {.lcid = bearer->logicalChannelIdentity, .priority = priority, .nssai = default_nssai};
|
||||
|
||||
/* Associate UE to the default slice*/
|
||||
/* consider first slice as default slice and assign it for SRBs */
|
||||
nr_pp_impl_param_dl_t *dl = &RC.nrmac[0]->pre_processor_dl;
|
||||
if (dl->slices) {
|
||||
c.nssai.sst = dl->slices->s[0]->nssai.sst;
|
||||
c.nssai.sd = dl->slices->s[0]->nssai.sd;
|
||||
}
|
||||
|
||||
nr_mac_add_lcid(&UE->UE_sched_ctrl, &c);
|
||||
LOG_I(NR_MAC, "%s(): Setting NSSAI sst: %d, sd: %d for SRB: %ld\n", __func__, c.nssai.sst, c.nssai.sd, bearer->servedRadioBearer->choice.srb_Identity);
|
||||
|
||||
// associate UEs to the first slice if slice exists (there is no DRB setup in this stage, associate SRB 1 to default slice)
|
||||
if (dl->slices) {
|
||||
dl->add_UE(dl->slices, UE);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ void nr_schedule_ue_spec(module_id_t module_id,
|
||||
nfapi_nr_tx_data_request_t *TX_req);
|
||||
|
||||
/* \brief default DL preprocessor init routine, returns preprocessor to call */
|
||||
nr_pp_impl_dl nr_init_dlsch_preprocessor(int CC_id);
|
||||
nr_pp_impl_param_dl_t nr_init_dlsch_preprocessor(int CC_id);
|
||||
|
||||
void schedule_nr_sib1(module_id_t module_idP,
|
||||
frame_t frameP,
|
||||
@@ -306,6 +306,8 @@ 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 nr_release_ra_UE(gNB_MAC_INST *mac, rnti_t rnti);
|
||||
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);
|
||||
NR_UE_info_t *find_ra_UE(NR_UEs_t *UEs, rnti_t rntiP);
|
||||
void delete_nr_ue_data(NR_UE_info_t *UE, NR_COMMON_channels_t *ccPtr, uid_allocator_t *uia);
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "lib/f1ap_ue_context.h"
|
||||
|
||||
#include "executables/softmodem-common.h"
|
||||
#include "openair2/LAYER2/NR_MAC_gNB/slicing/nr_slicing_common.h"
|
||||
|
||||
#include "uper_decoder.h"
|
||||
#include "uper_encoder.h"
|
||||
@@ -249,8 +250,23 @@ static int handle_ue_context_srbs_setup(NR_UE_info_t *UE,
|
||||
nr_rlc_add_srb(UE->rnti, srb->id, rlc_BearerConfig);
|
||||
|
||||
int priority = rlc_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->priority;
|
||||
nr_lc_config_t c = {.lcid = rlc_BearerConfig->logicalChannelIdentity, .priority = priority};
|
||||
nssai_t default_nssai = {.sst = 0, .sd = 0};
|
||||
nr_lc_config_t c = {.lcid = rlc_BearerConfig->logicalChannelIdentity, .priority = priority, .nssai = default_nssai};
|
||||
|
||||
/* Associate UE to the default slice*/
|
||||
/* consider first slice as default slice and assign it for SRBs */
|
||||
nr_pp_impl_param_dl_t *dl = &RC.nrmac[0]->pre_processor_dl;
|
||||
if (dl->slices) {
|
||||
c.nssai.sst = dl->slices->s[0]->nssai.sst;
|
||||
c.nssai.sd = dl->slices->s[0]->nssai.sd;
|
||||
}
|
||||
nr_mac_add_lcid(&UE->UE_sched_ctrl, &c);
|
||||
LOG_I(NR_MAC, "%s(): Setting NSSAI sst: %d, sd: %d for SRB: %d\n", __func__, c.nssai.sst, c.nssai.sd, srb->id);
|
||||
|
||||
// associate UEs to the first slice if slice exists (there is no DRB setup in this stage, associate SRB 2 to default slice
|
||||
if (dl->slices) {
|
||||
dl->add_UE(dl->slices, UE); // always add UE to the default slice first
|
||||
}
|
||||
|
||||
(*resp_srbs)[i].id = srb->id;
|
||||
(*resp_srbs)[i].lcid = c.lcid;
|
||||
@@ -340,6 +356,11 @@ static int handle_ue_context_drbs_setup(NR_UE_info_t *UE,
|
||||
}
|
||||
c.priority = prio;
|
||||
nr_mac_add_lcid(&UE->UE_sched_ctrl, &c);
|
||||
/* Associate UE to the corresponding slice */
|
||||
nr_pp_impl_param_dl_t *dl = &RC.nrmac[0]->pre_processor_dl;
|
||||
if (dl->slices) {
|
||||
dl->add_UE(dl->slices, UE); // always add UE to the default slice first
|
||||
}
|
||||
|
||||
resp_drb->id = drb->id;
|
||||
resp_drb->lcid = malloc_or_fail(sizeof(*resp_drb->lcid));
|
||||
@@ -799,6 +820,12 @@ void ue_context_setup_request(const f1ap_ue_context_setup_req_t *req)
|
||||
resp.du_to_cu_rrc_info.meas_gap_config = mgc;
|
||||
}
|
||||
|
||||
/* 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); // always add UE to the default slice first
|
||||
}
|
||||
|
||||
NR_SCHED_UNLOCK(&mac->sched_lock);
|
||||
|
||||
mac->mac_rrc.ue_context_setup_response(&resp);
|
||||
@@ -809,6 +836,16 @@ void ue_context_setup_request(const f1ap_ue_context_setup_req_t *req)
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_MeasurementTimingConfiguration, mtc);
|
||||
}
|
||||
|
||||
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 == 0;
|
||||
} else {
|
||||
return a_nssai.sst == b_sst && a_nssai.sd == *b_sd;
|
||||
}
|
||||
}
|
||||
|
||||
void ue_context_modification_request(const f1ap_ue_context_mod_req_t *req)
|
||||
{
|
||||
gNB_MAC_INST *mac = RC.nrmac[0];
|
||||
@@ -874,6 +911,18 @@ void ue_context_modification_request(const f1ap_ue_context_mod_req_t *req)
|
||||
c->suspended = false;
|
||||
LOG_I(NR_MAC, "UE %04x: Re-establishing RLC for LCID %d\n", UE->rnti, c->lcid);
|
||||
nr_rlc_reestablish_entity(req->gNB_DU_ue_id, c->lcid);
|
||||
// Update slice info
|
||||
nr_pp_impl_param_dl_t *dl = &mac->pre_processor_dl;
|
||||
if (dl->slices) {
|
||||
for (int s = 0; s < dl->slices->num; s++) {
|
||||
LOG_W(NR_MAC, "%s(), compare c->nssai %d.%06x with DL slice id %d nssai %d.%06x\n",
|
||||
__func__, c->nssai.sst, c->nssai.sd, dl->slices->s[s]->id, dl->slices->s[s]->nssai.sst, dl->slices->s[s]->nssai.sd);
|
||||
if (nssai_matches(c->nssai, dl->slices->s[s]->nssai.sst, &dl->slices->s[s]->nssai.sd)) {
|
||||
nr_mac_slice_add_lcid(&UE->UE_sched_ctrl.sliceInfoDl[s], c, dl->slices->s[s]->id);
|
||||
LOG_W(NR_MAC, "Add lcid %d to DL slice idx %d id %d\n", c->lcid, s, dl->slices->s[s]->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
UE->reestablish_rlc = false;
|
||||
}
|
||||
@@ -908,6 +957,11 @@ void ue_context_modification_request(const f1ap_ue_context_mod_req_t *req)
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->reconfigCellGroup);
|
||||
UE->reconfigCellGroup = new_CellGroup;
|
||||
configure_UE_BWP(mac, scc, UE, false, NR_SearchSpace__searchSpaceType_PR_common, -1, -1);
|
||||
/* 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); // always add UE to the default slice first
|
||||
}
|
||||
} else {
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, new_CellGroup); // we actually don't need it
|
||||
}
|
||||
@@ -1080,6 +1134,18 @@ void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc)
|
||||
nr_lc_config_t new = *c;
|
||||
new.suspended = true;
|
||||
nr_mac_add_lcid(&UE->UE_sched_ctrl, &new);
|
||||
// Update slice info
|
||||
nr_pp_impl_param_dl_t *dl = &mac->pre_processor_dl;
|
||||
if (dl->slices) {
|
||||
for (int s = 0; s < dl->slices->num; s++) {
|
||||
LOG_D(NR_MAC, "%s(), compare c->nssai %d.%06x with slice id %d nssai %d.%06x\n",
|
||||
__func__, c->nssai.sst, c->nssai.sd, dl->slices->s[s]->id, dl->slices->s[s]->nssai.sst, dl->slices->s[s]->nssai.sd);
|
||||
if (nssai_matches(new.nssai, dl->slices->s[s]->nssai.sst, &dl->slices->s[s]->nssai.sd)) {
|
||||
nr_mac_slice_add_lcid(&UE->UE_sched_ctrl.sliceInfoDl[s], &new, dl->slices->s[s]->id);
|
||||
LOG_D(NR_MAC, "Add lcid %d to DL slice idx %d id %d\n", c->lcid, s, dl->slices->s[s]->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->CellGroup);
|
||||
UE->CellGroup = oldUE->CellGroup;
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
#include "common/utils/T/T.h"
|
||||
#include "executables/softmodem-common.h"
|
||||
#include "linear_alloc.h"
|
||||
#include "slicing/nr_slicing_common.h"
|
||||
#include "nr_pdcp/nr_pdcp_entity.h"
|
||||
#include "nr_pdcp/nr_pdcp_oai_api.h"
|
||||
#include "nr_rlc/nr_rlc_oai_api.h"
|
||||
@@ -237,16 +238,33 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset
|
||||
end,
|
||||
"UE %04x: MAC: TX %14"PRIu64" RX %14"PRIu64" bytes\n",
|
||||
UE->rnti, stats->dl.total_bytes, stats->ul.total_bytes);
|
||||
|
||||
for (int i = 0; i < seq_arr_size(&sched_ctrl->lc_config); i++) {
|
||||
const nr_lc_config_t *c = seq_arr_at(&sched_ctrl->lc_config, i);
|
||||
output = st_append(output,
|
||||
end,
|
||||
"UE %04x: LCID %d: TX %14"PRIu64" RX %14"PRIu64" bytes\n",
|
||||
UE->rnti,
|
||||
c->lcid,
|
||||
stats->dl.lc_bytes[c->lcid],
|
||||
stats->ul.lc_bytes[c->lcid]);
|
||||
if (gNB->pre_processor_dl.slices) {
|
||||
for (int s = 0; s < gNB->pre_processor_dl.slices->num; s++) {
|
||||
for (int i = 0; i < seq_arr_size(&sched_ctrl->sliceInfoDl[s].lc_config); i++) {
|
||||
const nr_lc_config_t *c = seq_arr_at(&sched_ctrl->sliceInfoDl[s].lc_config, i);
|
||||
output = st_append(output,
|
||||
end,
|
||||
"UE %04x: LCID %d (dl-slice id %d, NSSAI %d.%06x): TX %14"PRIu64" RX %14"PRIu64" bytes\n",
|
||||
UE->rnti,
|
||||
c->lcid,
|
||||
gNB->pre_processor_dl.slices->s[s]->id,
|
||||
c->nssai.sst,
|
||||
c->nssai.sd,
|
||||
stats->dl.lc_bytes[c->lcid],
|
||||
stats->ul.lc_bytes[c->lcid]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < seq_arr_size(&sched_ctrl->lc_config); i++) {
|
||||
const nr_lc_config_t *c = seq_arr_at(&sched_ctrl->lc_config, i);
|
||||
output = st_append(output,
|
||||
end,
|
||||
"UE %04x: LCID %d: TX %14"PRIu64" RX %14"PRIu64" bytes\n",
|
||||
UE->rnti,
|
||||
c->lcid,
|
||||
stats->dl.lc_bytes[c->lcid],
|
||||
stats->ul.lc_bytes[c->lcid]);
|
||||
}
|
||||
}
|
||||
}
|
||||
DevAssert(output <= end);
|
||||
@@ -322,7 +340,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_dlsch_preprocessor(0);
|
||||
|
||||
@@ -602,6 +602,14 @@ typedef struct nr_lc_config {
|
||||
NR_QoS_config_t qos_config[NR_MAX_NUM_QFI];
|
||||
} nr_lc_config_t;
|
||||
|
||||
typedef struct {
|
||||
/// LCs in this slice
|
||||
seq_arr_t lc_config;
|
||||
/// amount of downlink 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 */
|
||||
typedef struct {
|
||||
/// CCE index and aggregation, should be coherent with cce_list
|
||||
@@ -696,6 +704,11 @@ typedef struct {
|
||||
/// sri, ul_ri and tpmi based on SRS
|
||||
nr_srs_feedback_t srs_feedback;
|
||||
|
||||
/// last scheduled downlink slice index
|
||||
int sched_dl_idx;
|
||||
/// hold information of slices
|
||||
NR_UE_slice_info_t sliceInfoDl[NR_MAX_NUM_SLICES];
|
||||
|
||||
/// per-LC configuration
|
||||
seq_arr_t lc_config;
|
||||
|
||||
@@ -797,6 +810,8 @@ typedef struct NR_UE_info {
|
||||
// dedicated BWP is always 1 from the UE's point of view, even if the gNB has multiple BWPs.
|
||||
// The below ID is the "true" (non-consecutive) BWP ID from the gNB's point of view
|
||||
NR_BWP_Id_t local_bwp_id;
|
||||
/// Assoc slice id
|
||||
NR_list_t dl_id;
|
||||
} NR_UE_info_t;
|
||||
|
||||
typedef struct {
|
||||
@@ -855,6 +870,66 @@ typedef struct gNB_MAC_INST_s gNB_MAC_INST;
|
||||
typedef void (*nr_pp_impl_dl)(gNB_MAC_INST *nr_mac, post_process_pdsch_t *pp_pdsch);
|
||||
typedef void (*nr_pp_impl_ul)(gNB_MAC_INST *nr_mac, post_process_pusch_t *pp_pusch);
|
||||
|
||||
/**
|
||||
* definition of a scheduling algorithm implementation used in the
|
||||
* default DL scheduler
|
||||
*/
|
||||
typedef struct {
|
||||
char *name;
|
||||
void *(*setup)(void);
|
||||
void (*unset)(void **);
|
||||
void (*run)(gNB_MAC_INST *, post_process_pdsch_t *, NR_UE_info_t **, int, int, int *, void *);
|
||||
void *data;
|
||||
} nr_dl_sched_algo_t;
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
void *(*setup)(void);
|
||||
void (*unset)(void **);
|
||||
int (*run)(gNB_MAC_INST *, post_process_pusch_t *, int, const NR_tda_info_t *, NR_UE_info_t **, int, int, int *, void *);
|
||||
void *data;
|
||||
} nr_ul_sched_algo_t;
|
||||
|
||||
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, -1 means don't move (no-op).
|
||||
void (*move_UE)(struct nr_slice_info_s *s, NR_UE_info_t* assoc_ue, int new_idx);
|
||||
/// get UE associated slice's index
|
||||
int (*get_UE_slice_idx)(struct nr_slice_info_s *s, rnti_t rnti);
|
||||
/// get the list of the slices of UE
|
||||
seq_arr_t (*get_UE_slice_idx_list)(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;
|
||||
@@ -970,7 +1045,7 @@ typedef struct gNB_MAC_INST_s {
|
||||
frame_structure_t frame_structure;
|
||||
|
||||
/// 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;
|
||||
|
||||
|
||||
254
openair2/LAYER2/NR_MAC_gNB/slicing/nr_slicing_common.c
Normal file
254
openair2/LAYER2/NR_MAC_gNB/slicing/nr_slicing_common.c
Normal file
@@ -0,0 +1,254 @@
|
||||
#include "nr_slicing_common.h"
|
||||
#include "../mac_proto.h"
|
||||
#include "assert.h"
|
||||
#include "common/utils/alg/find.h"
|
||||
|
||||
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, "%s(): si->UE_list[%d]->rnti %x map to rnti %x\n", __func__, 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;
|
||||
}
|
||||
|
||||
seq_arr_t nr_slicing_get_UE_slice_idx_list(nr_slice_info_t *si, rnti_t rnti)
|
||||
{
|
||||
assert(si != NULL);
|
||||
|
||||
seq_arr_t list;
|
||||
seq_arr_init(&list, sizeof(int));
|
||||
|
||||
for (int s_idx = 0; s_idx < si->num; s_idx++) {
|
||||
nr_slice_t *s = si->s[s_idx];
|
||||
LOG_D(NR_MAC, "id %d, num UEs %d\n", s->id, s->num_UEs);
|
||||
UE_iterator(s->UE_list, UE) {
|
||||
if (UE->rnti == rnti) {
|
||||
LOG_D(NR_MAC, "%s(): UE rnti %4x is associated with slice idx %d id %d\n", __func__, rnti, s_idx, s->id);
|
||||
seq_arr_push_back(&list, &s_idx, sizeof(int));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
/*
|
||||
// return the list of the slices that UE is associated with
|
||||
void print_UE_slice_idx_list(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) {
|
||||
LOG_D(NR_MAC, "%s(): UE %d is associated with slice idx %d and id %d \n", __func__, rnti, s_len, si->s[s_len]->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// print the list of the slices that UE is associated with
|
||||
void print_NR_list(NR_list_t *list)
|
||||
{
|
||||
if (list->head != -1) {
|
||||
int current = list->head;
|
||||
while (current != -1) {
|
||||
LOG_D(NR_MAC, "%s(): UE %d is associated with slice %d \n", __func__, current, list->next[current]);
|
||||
current = list->next[current];
|
||||
}
|
||||
} else {
|
||||
LOG_E(NR_MAC, "The list is empty.\n");
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
int _nr_exists_slice(uint8_t n, nr_slice_t **s, int id)
|
||||
{
|
||||
for (int i = 0; i < n; ++i) {
|
||||
LOG_D(NR_MAC, "%s(): n %d, s[%d]->id %d, id %d\n", __func__, 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;
|
||||
}
|
||||
|
||||
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 == 0;
|
||||
} else {
|
||||
return a_nssai.sst == b_sst && a_nssai.sd == *b_sd;
|
||||
}
|
||||
}
|
||||
|
||||
static bool eq_lcid_config(const void *vval, const void *vit)
|
||||
{
|
||||
const nr_lc_config_t *val = (const nr_lc_config_t *)vval;
|
||||
const nr_lc_config_t *it = (const nr_lc_config_t *)vit;
|
||||
return it->lcid == val->lcid;
|
||||
}
|
||||
|
||||
static int cmp_lc_config(const void *va, const void *vb)
|
||||
{
|
||||
const nr_lc_config_t *a = (const nr_lc_config_t *)va;
|
||||
const nr_lc_config_t *b = (const nr_lc_config_t *)vb;
|
||||
|
||||
if (a->priority < b->priority)
|
||||
return -1;
|
||||
if (a->priority == b->priority)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Add LCID in sliceInfoDl
|
||||
bool nr_mac_slice_add_lcid(NR_UE_slice_info_t* slice, const nr_lc_config_t *c, const uint32_t id)
|
||||
{
|
||||
elm_arr_t elm = find_if(&slice->lc_config, (void *) c, eq_lcid_config);
|
||||
if (elm.found) {
|
||||
LOG_D(NR_MAC, "cannot add LCID %d in slice: already present, updating configuration\n", c->lcid);
|
||||
nr_lc_config_t *exist = (nr_lc_config_t *)elm.it;
|
||||
*exist = *c;
|
||||
} else {
|
||||
LOG_D(NR_MAC, "Add LCID %d in slice id %d\n", c->lcid, id);
|
||||
seq_arr_push_back(&slice->lc_config, (void*) c, sizeof(*c));
|
||||
}
|
||||
void *base = seq_arr_front(&slice->lc_config);
|
||||
size_t nmemb = seq_arr_size(&slice->lc_config);
|
||||
size_t size = sizeof(*c);
|
||||
qsort(base, nmemb, size, cmp_lc_config);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Use RC SM to add UE to DL slices
|
||||
void nr_slicing_rcsm_dl_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");
|
||||
AssertFatal(new_ue != NULL, "UE is NULL\n");
|
||||
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &new_ue->UE_sched_ctrl;
|
||||
|
||||
reset_nr_list(&new_ue->dl_id);
|
||||
|
||||
for (int i = 0; i < si->num; ++i) {
|
||||
nr_slice_t* s = si->s[i];
|
||||
for (size_t l = 0; l < seq_arr_size(&sched_ctrl->lc_config); ++l) {
|
||||
const nr_lc_config_t *c = seq_arr_at(&sched_ctrl->lc_config, l);
|
||||
long lcid = c->lcid;
|
||||
if (nssai_matches(c->nssai, s->nssai.sst, &s->nssai.sd)) {
|
||||
|
||||
nr_mac_slice_add_lcid(&new_ue->UE_sched_ctrl.sliceInfoDl[i], c, s->id);
|
||||
LOG_D(NR_MAC, "Add lcid %ld to DL slice idx %d\n", lcid, i);
|
||||
|
||||
if (!check_nr_list(&new_ue->dl_id, s->id)) {
|
||||
add_nr_list(&new_ue->dl_id, s->id);
|
||||
LOG_D(NR_MAC, "Add DL slice id %d to new UE rnti %x\n", s->id, new_ue->rnti);
|
||||
}
|
||||
|
||||
// make sure new_ue is not in the s->UE_list before add
|
||||
bool add_UE = true;
|
||||
UE_iterator(s->UE_list, UE) {
|
||||
if (UE->rnti == new_ue->rnti) {
|
||||
LOG_D(NR_MAC, "UE rnti 0x%04x exists in DL slice idx %d, sst %d, sd %06x\n", new_ue->rnti, i, s->nssai.sst, s->nssai.sd);
|
||||
add_UE = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (add_UE) {
|
||||
bool success = add_UE_to_list(MAX_MOBILES_PER_GNB, s->UE_list, new_ue);
|
||||
s->num_UEs += 1;
|
||||
AssertFatal(success, "Try to add UE but the s->UE_list is full\n");
|
||||
LOG_A(NR_MAC, "Matched DL slice, Add UE rnti 0x%04x to DL slice idx %d, sst %d, sd %06x\n",
|
||||
new_ue->rnti, i, s->nssai.sst, s->nssai.sd);
|
||||
} else {
|
||||
LOG_D(NR_MAC, "Cannot add new UE rnti 0x%04x to DL slice idx %d, num_UEs %d\n",
|
||||
new_ue->rnti, i, s->num_UEs);
|
||||
}
|
||||
} else {
|
||||
LOG_D(NR_MAC, "Cannot find matched DL slice (lcid %ld <sst %d sd %d>, DL slice idx %d <sst %d sd %d>), do nothing for UE rnti 0x%04x\n",
|
||||
lcid, c->nssai.sst, c->nssai.sd, i, s->nssai.sst, s->nssai.sd, new_ue->rnti);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove UE from DL slices list
|
||||
void nr_slicing_dl_remove_UE_from_list(nr_slice_info_t *si, NR_UE_info_t* rm_ue, int idx)
|
||||
{
|
||||
AssertFatal(si->num > 0 && si->s != NULL, "no slices exists, cannot remove UEs\n");
|
||||
AssertFatal(rm_ue != NULL, "UE is NULL\n");
|
||||
|
||||
nr_slice_t* s = si->s[idx];
|
||||
|
||||
// this is for deassociation, in other case that UE disconnects, r->dl_id will be destroyed at delete_nr_ue_data()
|
||||
if (check_nr_list(&rm_ue->dl_id, s->id)) {
|
||||
remove_nr_list(&rm_ue->dl_id, s->id);
|
||||
LOG_I(NR_MAC, "Remove dl id %d from UE rnti 0x%04x\n", s->id, rm_ue->rnti);
|
||||
}
|
||||
|
||||
// make sure rm_ue is in the si->s[idx]->UE_list before remove
|
||||
bool remove_UE = false;
|
||||
UE_iterator(s->UE_list, ue) {
|
||||
if (ue->rnti == rm_ue->rnti) {
|
||||
LOG_D(NR_MAC, "UE rnti 0x%04x exists in DL slice id %d\n", rm_ue->rnti, s->id);
|
||||
remove_UE = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (remove_UE) {
|
||||
NR_UE_info_t *r = remove_UE_from_list(NR_NB_RA_PROC_MAX, s->UE_list, rm_ue->rnti);
|
||||
DevAssert(r == rm_ue);
|
||||
si->s[idx]->num_UEs -= 1;
|
||||
LOG_A(NR_MAC, "Remove UE rnti 0x%04x from DL slice id %d, num UEs %d\n", rm_ue->rnti, s->id, s->num_UEs);
|
||||
}
|
||||
//print_UE_slice_idx_list(si, rm_ue->rnti);
|
||||
}
|
||||
|
||||
|
||||
56
openair2/LAYER2/NR_MAC_gNB/slicing/nr_slicing_common.h
Normal file
56
openair2/LAYER2/NR_MAC_gNB/slicing/nr_slicing_common.h
Normal file
@@ -0,0 +1,56 @@
|
||||
#ifndef NR_SLICING_COMMON_H
|
||||
#define NR_SLICING_COMMON_H
|
||||
|
||||
#include "openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h"
|
||||
|
||||
typedef struct nr_slice_s {
|
||||
/// Arbitrary ID
|
||||
slice_id_t id;
|
||||
/// 3GPP slice id
|
||||
nssai_t nssai;
|
||||
/// Arbitrary label
|
||||
char *label;
|
||||
|
||||
union {
|
||||
nr_dl_sched_algo_t dl_algo;
|
||||
nr_ul_sched_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
|
||||
int num_UEs;
|
||||
NR_UE_info_t *UE_list[MAX_MOBILES_PER_GNB+1];
|
||||
} nr_slice_t;
|
||||
|
||||
typedef struct nr_slice_info_s {
|
||||
uint8_t num;
|
||||
nr_slice_t **s;
|
||||
} nr_slice_info_t;
|
||||
|
||||
bool nr_mac_slice_add_lcid(NR_UE_slice_info_t* slice, const nr_lc_config_t *c, const uint32_t id);
|
||||
|
||||
int nr_slicing_get_UE_slice_idx(nr_slice_info_t *si, rnti_t rnti);
|
||||
|
||||
seq_arr_t nr_slicing_get_UE_slice_idx_list(nr_slice_info_t *si, rnti_t rnti);
|
||||
|
||||
int nr_slicing_get_UE_idx(nr_slice_t *si, rnti_t rnti);
|
||||
|
||||
int _nr_exists_slice(uint8_t n, nr_slice_t **s, int id);
|
||||
|
||||
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);
|
||||
|
||||
void nr_slicing_rcsm_dl_add_UE(nr_slice_info_t *si, NR_UE_info_t *new_ue);
|
||||
|
||||
void nr_slicing_dl_move_UE_from_list(nr_slice_info_t *si, NR_UE_info_t* assoc_ue, int new_idx);
|
||||
|
||||
void nr_slicing_dl_remove_UE_from_list(nr_slice_info_t *si, NR_UE_info_t* rm_ue, int idx);
|
||||
|
||||
int remove_nr_slice_dl_from_list(nr_slice_info_t *si, uint8_t slice_idx);
|
||||
|
||||
|
||||
#endif // NR_SLICING_COMMON_H
|
||||
348
openair2/LAYER2/NR_MAC_gNB/slicing/nr_slicing_nvs_rcsm.c
Normal file
348
openair2/LAYER2/NR_MAC_gNB/slicing/nr_slicing_nvs_rcsm.c
Normal file
@@ -0,0 +1,348 @@
|
||||
#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 "NR_MAC_COMMON/nr_mac.h"
|
||||
#include "openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h"
|
||||
#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h"
|
||||
|
||||
#include "nr_slicing_common.h"
|
||||
#include "nr_slicing_nvs_rcsm.h"
|
||||
|
||||
#include "executables/softmodem-common.h"
|
||||
|
||||
extern RAN_CONTEXT_t RC;
|
||||
|
||||
#define RET_FAIL(ret, x...) do { LOG_E(MAC, x); return ret; } while (0)
|
||||
|
||||
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;
|
||||
|
||||
static 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) {
|
||||
LOG_D(NR_MAC, "i %d, idx %d\n", i, idx);
|
||||
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 {
|
||||
LOG_D(NR_MAC, "slice idx %d, si->num %d, pct_reserved %.2f, sum_req %.2f\n", i, si->num, sp->pct_reserved, sum_req);
|
||||
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;
|
||||
}
|
||||
|
||||
static 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;
|
||||
}
|
||||
|
||||
void nvs_nr_dl(gNB_MAC_INST *mac, post_process_pdsch_t *pp_pdsch)
|
||||
{
|
||||
NR_UEs_t *UE_info = &mac->UE_info;
|
||||
if (UE_info->connected_ue_list[0] == NULL)
|
||||
return;
|
||||
|
||||
/* check if we are supposed to schedule something */
|
||||
NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon;
|
||||
int bw = scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth;
|
||||
int num_beams = mac->beam_info.beam_allocation ? mac->beam_info.beams_per_period : 1;
|
||||
AssertFatal(num_beams == 1, "we do not support multiple beam in PR slicing algorithm\n");
|
||||
int remain_n_rb_sched[num_beams];
|
||||
int original_n_rb_sched[num_beams];
|
||||
for (int i = 0; i < num_beams; i++) {
|
||||
remain_n_rb_sched[i] = bw;
|
||||
original_n_rb_sched[i] = bw;
|
||||
}
|
||||
|
||||
int average_agg_level = 4; // TODO find a better estimation
|
||||
int max_sched_ues = bw / (average_agg_level * NR_NB_REG_PER_CCE);
|
||||
|
||||
// FAPI cannot handle more than MAX_DCI_CORESET DCIs
|
||||
max_sched_ues = min(max_sched_ues, MAX_DCI_CORESET);
|
||||
|
||||
/* Schedule slices */
|
||||
nr_slice_info_t *si = mac->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->sliceInfoDl[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) {
|
||||
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;
|
||||
|
||||
/* Calculate the exponential moving average for throughput */
|
||||
ip->eff = (1.0f - ip->beta_eff) * ip->eff + ip->beta_eff * inst;
|
||||
|
||||
/* Calculate the exponential moving average for current with scheduled slice */
|
||||
ip->exp += BETA * inst;
|
||||
}
|
||||
|
||||
const float rsv = p->Mbps_reserved * min(1.0f, ip->eff / p->Mbps_reference);
|
||||
|
||||
/* Calculate the weight for the slice */
|
||||
w = rsv / ip->exp;
|
||||
|
||||
/* Calculate the exponential moving average for next for the slice */
|
||||
ip->exp = (1 - BETA) * ip->exp;
|
||||
|
||||
/* Check exp and eff overflow */
|
||||
if (ip->rb == 0) {
|
||||
if (ip->exp == (1 - BETA) * ip->exp || ip->eff == (1.0f - ip->beta_eff) * ip->eff) {
|
||||
/* Reload parameters */
|
||||
ip->exp = p->Mbps_reserved / p->Mbps_reference;
|
||||
ip->eff = p->Mbps_reference;
|
||||
}
|
||||
}
|
||||
} else { /* NVS CAPACITY */
|
||||
/* Calculate the exponential moving average for current with scheduled slice */
|
||||
if (ip->rb > 0) {
|
||||
ip->exp += BETA;
|
||||
}
|
||||
|
||||
/* Calculate the weight for the slice */
|
||||
w = p->pct_reserved / (ip->exp);
|
||||
|
||||
/* Calculate the exponential moving average for next for the slice */
|
||||
ip->exp = (1.0f - BETA) * 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;
|
||||
|
||||
/* Find the max weight */
|
||||
if (w > maxw) {
|
||||
maxw = w;
|
||||
maxidx = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (maxidx < 0)
|
||||
return;
|
||||
|
||||
/* Statistic */
|
||||
static int counter[MAX_NVS_SLICES] = {0};
|
||||
static int times = 0;
|
||||
counter[maxidx]++;
|
||||
times++;
|
||||
if (pp_pdsch->frame % 100 == 0 && pp_pdsch->slot == 0) {
|
||||
for (int i = 0; i < si->num; ++i) {
|
||||
LOG_D(NR_MAC,
|
||||
"[NVS Statistic DL] Slice Id %d, counter %d, probabilities %f\n",
|
||||
si->s[i]->id,
|
||||
counter[i],
|
||||
(float)counter[i] / times);
|
||||
counter[i] = 0;
|
||||
}
|
||||
times = 0;
|
||||
}
|
||||
|
||||
// TODO: now is one beam associates to multiple slices
|
||||
((_nvs_int_t *)si->s[maxidx]->int_data)->rb = remain_n_rb_sched[0];
|
||||
|
||||
UE_iterator (si->s[maxidx]->UE_list, UE) {
|
||||
UE->UE_sched_ctrl.sched_dl_idx = maxidx;
|
||||
LOG_D(NR_MAC, "UE %4x sched_dl_idx %d\n", UE->rnti, UE->UE_sched_ctrl.sched_dl_idx);
|
||||
LOG_D(NR_MAC, "%4d.%2d schedule UE %4x at slice idx %d ID %d \n", pp_pdsch->frame, pp_pdsch->slot, UE->rnti, maxidx, si->s[maxidx]->id);
|
||||
}
|
||||
|
||||
/* proportional fair scheduling algorithm */
|
||||
si->s[maxidx]->dl_algo.run(mac,
|
||||
pp_pdsch,
|
||||
si->s[maxidx]->UE_list,
|
||||
max_sched_ues,
|
||||
num_beams,
|
||||
remain_n_rb_sched,
|
||||
si->s[maxidx]->dl_algo.data);
|
||||
for (int i = 0; i < num_beams; i++) {
|
||||
if (original_n_rb_sched[i] - remain_n_rb_sched[i] > 0)
|
||||
LOG_D(NR_MAC, "%4d.%2d schedule %d RBs at slice idx %d ID %d \n", pp_pdsch->frame, pp_pdsch->slot, original_n_rb_sched[i] - remain_n_rb_sched[i], maxidx, si->s[maxidx]->id);
|
||||
|
||||
if (remain_n_rb_sched[i] == original_n_rb_sched[i]) // 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_rcsm_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);
|
||||
|
||||
/* 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 = 0, .sd = 0};
|
||||
|
||||
const int rc = addmod_nvs_nr_slice_dl(si, 0, nssai, strdup("default"), algo, dlp);
|
||||
DevAssert(0 == rc);
|
||||
|
||||
LOG_A(NR_MAC, "%s(): add default DL slice id 0, label default, sst %d, sd %d\n",__func__, nssai.sst, nssai.sd);
|
||||
|
||||
nr_pp_impl_param_dl_t nvs;
|
||||
nvs.algorithm = NVS_SLICING;
|
||||
nvs.get_UE_slice_idx = nr_slicing_get_UE_slice_idx;
|
||||
nvs.get_UE_slice_idx_list = nr_slicing_get_UE_slice_idx_list;
|
||||
nvs.get_UE_idx = nr_slicing_get_UE_idx;
|
||||
nvs.add_UE = nr_slicing_rcsm_dl_add_UE;
|
||||
nvs.move_UE = NULL; // move UE function is not defined by the RC ctrl
|
||||
nvs.remove_UE = nr_slicing_dl_remove_UE_from_list;
|
||||
nvs.addmod_slice = addmod_nvs_nr_slice_dl;
|
||||
nvs.remove_slice = NULL; // remove function is not defined by the RC ctrl
|
||||
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;
|
||||
}
|
||||
28
openair2/LAYER2/NR_MAC_gNB/slicing/nr_slicing_nvs_rcsm.h
Normal file
28
openair2/LAYER2/NR_MAC_gNB/slicing/nr_slicing_nvs_rcsm.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#include "openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h"
|
||||
|
||||
#ifndef NR_SLICING_NVS_RCSM_H
|
||||
#define NR_SLICING_NVS_RCSM_H
|
||||
|
||||
#define NVS_SLICING 20
|
||||
#define MAX_NVS_SLICES 10
|
||||
#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_rcsm_dl_init(module_id_t mod_id);
|
||||
|
||||
#endif /* NR_SLICING_NVS_RCSM_H */
|
||||
@@ -171,7 +171,7 @@ void start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id_t ue_id, int pdu_sess
|
||||
threadCreate(&entity->pdusession_thread, sdap_tun_read_thread, entity, "gnb_tun_read_thread", -1, OAI_PRIORITY_RT_LOW);
|
||||
}
|
||||
|
||||
static void start_sdap_tun_ue(ue_id_t ue_id, int pdu_session_id, int sock, const char *ifname)
|
||||
static void start_sdap_tun_ue(ue_id_t ue_id, int pdu_session_id, int sock, int tunid, const char *ifname)
|
||||
{
|
||||
nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, pdu_session_id);
|
||||
DevAssert(entity != NULL);
|
||||
@@ -180,7 +180,7 @@ static void start_sdap_tun_ue(ue_id_t ue_id, int pdu_session_id, int sock, const
|
||||
entity->pdusession_if_name = strdup(ifname);
|
||||
entity->stop_thread = false;
|
||||
char thread_name[64];
|
||||
snprintf(thread_name, sizeof(thread_name), "ue_tun_read_%ld_p%d", ue_id, pdu_session_id);
|
||||
snprintf(thread_name, sizeof(thread_name), "ue_tun_read_%d_p%d", tunid, pdu_session_id);
|
||||
threadCreate(&entity->pdusession_thread, sdap_tun_read_thread, entity, thread_name, -1, OAI_PRIORITY_RT_LOW);
|
||||
}
|
||||
|
||||
@@ -188,22 +188,22 @@ static void start_sdap_tun_ue(ue_id_t ue_id, int pdu_session_id, int sock, const
|
||||
void create_ue_ip_if(const char *ipv4, const char *ipv6, int ue_id, int pdu_session_id, bool is_default)
|
||||
{
|
||||
char ifname[IFNAMSIZ];
|
||||
tuntap_generate_ue_ifname(ifname, IFF_TUN, ue_id, is_default ? -1 : pdu_session_id);
|
||||
int tunid = tuntap_generate_ue_ifname(ifname, IFF_TUN, ue_id, is_default ? -1 : pdu_session_id);
|
||||
const int sock = tuntap_alloc(IFF_TUN, ifname);
|
||||
tun_config(ifname, ipv4, ipv6);
|
||||
if (ipv4) {
|
||||
setup_ue_ipv4_route(ifname, ue_id, ipv4);
|
||||
setup_ue_ipv4_route(ifname, tunid, ipv4);
|
||||
}
|
||||
start_sdap_tun_ue(ue_id, pdu_session_id, sock, ifname); // interface name suffix is ue_id+1
|
||||
start_sdap_tun_ue(ue_id, pdu_session_id, sock, tunid, ifname); // interface name suffix is ue_id+1
|
||||
}
|
||||
|
||||
void create_ue_eth_if(int ue_id, int pdu_session_id, bool is_default)
|
||||
{
|
||||
char ifname[IFNAMSIZ];
|
||||
tuntap_generate_ue_ifname(ifname, IFF_TAP, ue_id, is_default ? -1 : pdu_session_id);
|
||||
int tunid = tuntap_generate_ue_ifname(ifname, IFF_TAP, ue_id, is_default ? -1 : pdu_session_id);
|
||||
const int sock = tuntap_alloc(IFF_TAP, ifname);
|
||||
tap_config(ifname); // brings the interface up
|
||||
start_sdap_tun_ue(ue_id, pdu_session_id, sock, ifname);
|
||||
start_sdap_tun_ue(ue_id, pdu_session_id, sock, tunid, ifname);
|
||||
}
|
||||
|
||||
void remove_ip_if(nr_sdap_entity_t *entity)
|
||||
|
||||
Reference in New Issue
Block a user