mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-21 08:30:31 +00:00
Compare commits
26 Commits
rs
...
slicing-sp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50d33e69f0 | ||
|
|
1db9ad510c | ||
|
|
f5162e263d | ||
|
|
61e94b68ac | ||
|
|
383610ddc2 | ||
|
|
2acb7f14d3 | ||
|
|
ba461b841d | ||
|
|
fea1344c24 | ||
|
|
3285245a08 | ||
|
|
da86353fa5 | ||
|
|
4c8feea3c9 | ||
|
|
b5f5156889 | ||
|
|
df88353da7 | ||
|
|
7ee34580a7 | ||
|
|
f6662356b6 | ||
|
|
6e52cc7b2e | ||
|
|
99e8ba4307 | ||
|
|
724b742280 | ||
|
|
bfe7d83881 | ||
|
|
88f2ac7c57 | ||
|
|
8a97251ae2 | ||
|
|
fded7890e6 | ||
|
|
aa695207a7 | ||
|
|
0837edad33 | ||
|
|
a894f52fda | ||
|
|
e606cfa2d3 |
@@ -1365,6 +1365,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
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -72,3 +72,17 @@ byte_array_t cp_str_to_ba(const char* str)
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
char* cp_ba_to_str(const byte_array_t ba)
|
||||
{
|
||||
assert(ba.len > 0);
|
||||
|
||||
const size_t sz = ba.len;
|
||||
char* str = calloc(sz+1, sizeof(char));
|
||||
assert(str != NULL && "Memory exhausted");
|
||||
|
||||
memcpy(str, ba.buf, sz);
|
||||
str[sz] = '\0';
|
||||
|
||||
return str;
|
||||
}
|
||||
@@ -42,5 +42,5 @@ void free_byte_array(byte_array_t ba);
|
||||
bool eq_byte_array(const byte_array_t* m0, const byte_array_t* m1);
|
||||
|
||||
byte_array_t cp_str_to_ba(const char* str);
|
||||
|
||||
char* cp_ba_to_str(const byte_array_t ba);
|
||||
#endif
|
||||
|
||||
@@ -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
|
||||
#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 */ \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -722,7 +722,7 @@ int main(int argc, char **argv)
|
||||
nr_mac_add_test_ue(RC.nrmac[0], secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity, secondaryCellGroup);
|
||||
// reset preprocessor to the one of DLSIM after it has been set during
|
||||
// nr_mac_config_scc()
|
||||
gNB_mac->pre_processor_dl = nr_dlsim_preprocessor;
|
||||
gNB_mac->pre_processor_dl.dl = nr_dlsim_preprocessor;
|
||||
phy_init_nr_gNB(gNB);
|
||||
N_RB_DL = gNB->frame_parms.N_RB_DL;
|
||||
NR_UE_info_t *UE_info = RC.nrmac[0]->UE_info.list[0];
|
||||
|
||||
@@ -1,43 +1,51 @@
|
||||
add_library(e2_ran_func_cuup STATIC
|
||||
init_ran_func.c
|
||||
read_setup_ran.c
|
||||
../flexric/test/rnd/fill_rnd_data_e2_setup_req.c # this is not rnd data; it is used to fill E2 Node Component Configuration Addition List in E2 Setup Request message
|
||||
CUSTOMIZED/ran_func_gtp.c # current implementation doesn't take split architecture into account, neither CU/DU nor CU-UP/CU-CP
|
||||
CUSTOMIZED/ran_func_pdcp.c # current implementation doesn't take split architecture into account, neither CU/DU nor CU-UP/CU-CP
|
||||
O-RAN/ran_e2sm_ue_id.c
|
||||
O-RAN/ran_func_kpm.c
|
||||
O-RAN/ran_func_kpm_subs.c
|
||||
O-RAN/ran_func_rc.c
|
||||
O-RAN/ran_func_rc_subs.c
|
||||
CUSTOMIZED/ran_func_gtp.c # GTP SM not yet implemented in CU-UP
|
||||
CUSTOMIZED/ran_func_pdcp.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_kpm.c # this file should only contain PDCP-U/GTP; to be done in the future
|
||||
../flexric/test/rnd/fill_rnd_data_kpm.c # this dependancy will be taken out once RAN Function Definition is implemented
|
||||
O-RAN/ran_func_rc.c # this file should only contain PDCP-U/GTP; to be done in the future
|
||||
O-RAN/ran_func_rc_subs.c
|
||||
../flexric/test/rnd/fill_rnd_data_rc.c # this dependancy will be taken out once RAN Function Definition is implemented
|
||||
)
|
||||
|
||||
target_link_libraries(e2_ran_func_cuup PUBLIC asn1_nr_rrc nr_rrc asn1_nr_rrc_hdrs e2_time_obj kpm_ric_info_common_obj 3gpp_derived_ie_obj)
|
||||
target_link_libraries(e2_ran_func_cuup PUBLIC asn1_nr_rrc nr_rrc asn1_nr_rrc_hdrs e2_time_obj kpm_ric_info_common_obj 3gpp_derived_ie_obj sm_common_ie_obj)
|
||||
target_compile_definitions(e2_ran_func_cuup PUBLIC ${E2AP_VERSION} ${KPM_VERSION} NGRAN_GNB_CUUP)
|
||||
|
||||
|
||||
add_library(e2_ran_func_du_cucp_cuup STATIC
|
||||
init_ran_func.c
|
||||
read_setup_ran.c
|
||||
../flexric/test/rnd/fill_rnd_data_e2_setup_req.c # this is not rnd data; it is used to fill E2 Node Component Configuration Addition List in E2 Setup Request message
|
||||
CUSTOMIZED/ran_func_gtp.c # current implementation doesn't take split architecture into account, neither CU/DU nor CU-UP/CU-CP
|
||||
CUSTOMIZED/ran_func_pdcp.c # current implementation doesn't take split architecture into account, neither CU/DU nor CU-UP/CU-CP
|
||||
O-RAN/ran_func_kpm.c # this file should only contain RRC/PDCP-C; to be done in the future
|
||||
# when nr-softmodem is divided in separate executables
|
||||
../flexric/test/rnd/fill_rnd_data_kpm.c # this dependancy will be taken out once RAN Function Definition is implemented
|
||||
O-RAN/ran_func_rc.c # this file should only contain RRC/PDCP-C; to be done in the future
|
||||
# when nr-softmodem is divided in separate executables
|
||||
O-RAN/ran_e2sm_ue_id.c
|
||||
O-RAN/ran_func_kpm.c
|
||||
O-RAN/ran_func_kpm_subs.c
|
||||
O-RAN/ran_func_rc.c
|
||||
O-RAN/ran_func_rc_subs.c
|
||||
../flexric/test/rnd/fill_rnd_data_rc.c # this dependancy will be taken out once RAN Function Definition is implemented
|
||||
O-RAN/rc_ctrl_service_style_2.c
|
||||
../flexric/src/sm/rc_sm/ie/rc_data_ie.c
|
||||
CUSTOMIZED/ran_func_gtp.c
|
||||
CUSTOMIZED/ran_func_pdcp.c
|
||||
CUSTOMIZED/ran_func_mac.c
|
||||
CUSTOMIZED/ran_func_rlc.c
|
||||
CUSTOMIZED/ran_func_slice.c
|
||||
CUSTOMIZED/ran_func_tc.c
|
||||
../flexric/test/rnd/fill_rnd_data_tc.c
|
||||
CUSTOMIZED/ran_func_slice.c # currently, not implemented; therefore, filling rnd data
|
||||
../flexric/test/rnd/fill_rnd_data_slice.c
|
||||
../../LAYER2/NR_MAC_gNB/slicing/nr_slicing.c
|
||||
CUSTOMIZED/ran_func_tc.c # currently, not implemented; therefore, filling rnd data
|
||||
../flexric/test/rnd/fill_rnd_data_tc.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 e2_agent)
|
||||
target_compile_definitions(e2_ran_func_du_cucp_cuup PUBLIC ${E2AP_VERSION} ${KPM_VERSION} NGRAN_GNB_DU NGRAN_GNB_CUCP NGRAN_GNB_CUUP)
|
||||
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)
|
||||
target_compile_definitions(e2_ran_func_du_cucp_cuup PUBLIC ${E2AP_VERSION} ${KPM_VERSION} NGRAN_GNB_DU NGRAN_GNB_CUCP NGRAN_GNB_CUUP)
|
||||
|
||||
# Current implementation:
|
||||
# - we only have one executable nr-softmodem for 4 node types: DU, CU, gNB-mono, CU-CP
|
||||
|
||||
# In the future, when nr-softmodem is separated, linking should be done as following:
|
||||
# - DU: e2_ran_func_du
|
||||
# - CU-CP : e2_ran_func_cucp
|
||||
# - CU-UP: e2_ran_func_cuup (this is available at the moment, executable nr-cuup)
|
||||
# - CU: e2_ran_func_cucp + e2_ran_func_cuup
|
||||
# - gNB-mono: e2_ran_func_du + e2_ran_func_cucp + e2_ran_func_cuup
|
||||
|
||||
@@ -44,7 +44,7 @@ bool read_gtp_sm(void * data)
|
||||
|
||||
uint64_t ue_id_list[MAX_MOBILES_PER_GNB];
|
||||
size_t num_ues = nr_pdcp_get_num_ues(ue_id_list, MAX_MOBILES_PER_GNB);
|
||||
|
||||
|
||||
gtp->msg.len = num_ues;
|
||||
if(gtp->msg.len > 0){
|
||||
gtp->msg.ngut = calloc(gtp->msg.len, sizeof(gtp_ngu_t_stats_t) );
|
||||
@@ -66,7 +66,7 @@ bool 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) {
|
||||
@@ -80,7 +80,7 @@ bool read_gtp_sm(void * data)
|
||||
#elif defined (NGRAN_GNB_CUUP)
|
||||
// For the moment, CU-UP doesn't store PDU session information
|
||||
printf("GTP SM not yet implemented in CU-UP\n");
|
||||
return false;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
143
openair2/E2AP/RAN_FUNCTION/O-RAN/ran_e2sm_ue_id.c
Normal file
143
openair2/E2AP/RAN_FUNCTION/O-RAN/ran_e2sm_ue_id.c
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "ran_e2sm_ue_id.h"
|
||||
|
||||
ue_id_e2sm_t fill_e2sm_gnb_ue_id_data(const gNB_RRC_UE_t *rrc_ue_context, __attribute__((unused))const uint32_t rrc_ue_id, __attribute__((unused))const ue_id_t cucp_ue_id)
|
||||
{
|
||||
ue_id_e2sm_t ue_id = {0};
|
||||
|
||||
ue_id.type = GNB_UE_ID_E2SM;
|
||||
|
||||
// 6.2.3.16
|
||||
// Mandatory
|
||||
// AMF UE NGAP ID
|
||||
ue_id.gnb.amf_ue_ngap_id = rrc_ue_context->amf_ue_ngap_id;
|
||||
|
||||
// Mandatory
|
||||
//GUAMI 6.2.3.17
|
||||
ue_id.gnb.guami.plmn_id = (e2sm_plmn_t) {
|
||||
.mcc = rrc_ue_context->ue_guami.mcc,
|
||||
.mnc = rrc_ue_context->ue_guami.mnc,
|
||||
.mnc_digit_len = rrc_ue_context->ue_guami.mnc_len
|
||||
};
|
||||
|
||||
ue_id.gnb.guami.amf_region_id = rrc_ue_context->ue_guami.amf_region_id;
|
||||
ue_id.gnb.guami.amf_set_id = rrc_ue_context->ue_guami.amf_set_id;
|
||||
ue_id.gnb.guami.amf_ptr = rrc_ue_context->ue_guami.amf_pointer;
|
||||
|
||||
// RAN UE ID
|
||||
// Optional
|
||||
// 6.2.3.25
|
||||
// OCTET STRING (SIZE (8))
|
||||
// Defined in TS 38.473 (F1AP)
|
||||
// clause 9.2.2.1
|
||||
// UE CONTEXT SETUP REQUEST
|
||||
ue_id.gnb.ran_ue_id = calloc(1, sizeof(uint64_t));
|
||||
assert(ue_id.gnb.ran_ue_id != NULL);
|
||||
*ue_id.gnb.ran_ue_id = rrc_ue_context->rrc_ue_id;
|
||||
|
||||
return ue_id;
|
||||
}
|
||||
|
||||
ue_id_e2sm_t fill_e2sm_cu_ue_id_data(const gNB_RRC_UE_t *rrc_ue_context, const uint32_t rrc_ue_id, const ue_id_t cucp_ue_id)
|
||||
{
|
||||
ue_id_e2sm_t ue_id = fill_e2sm_gnb_ue_id_data(rrc_ue_context, rrc_ue_id, cucp_ue_id);
|
||||
|
||||
// gNB-CU UE F1AP ID List
|
||||
// C-ifCUDUseparated
|
||||
ue_id.gnb.gnb_cu_ue_f1ap_lst_len = 1;
|
||||
ue_id.gnb.gnb_cu_ue_f1ap_lst = calloc(ue_id.gnb.gnb_cu_ue_f1ap_lst_len, sizeof(uint32_t));
|
||||
assert(ue_id.gnb.gnb_cu_ue_f1ap_lst != NULL && "Memory exhausted");
|
||||
ue_id.gnb.gnb_cu_ue_f1ap_lst[0] = rrc_ue_context->rrc_ue_id;
|
||||
|
||||
return ue_id;
|
||||
}
|
||||
|
||||
ue_id_e2sm_t fill_e2sm_du_ue_id_data(__attribute__((unused))const gNB_RRC_UE_t *rrc_ue_context, const uint32_t rrc_ue_id, __attribute__((unused))const ue_id_t cucp_ue_id)
|
||||
{
|
||||
ue_id_e2sm_t ue_id = {0};
|
||||
|
||||
ue_id.type = GNB_DU_UE_ID_E2SM;
|
||||
|
||||
// 6.2.3.21
|
||||
// gNB CU UE F1AP
|
||||
// Mandatory
|
||||
ue_id.gnb_du.gnb_cu_ue_f1ap = rrc_ue_id;
|
||||
|
||||
// 6.2.3.25
|
||||
// RAN UE ID
|
||||
// Optional
|
||||
ue_id.gnb_du.ran_ue_id = calloc(1, sizeof(uint64_t));
|
||||
assert(ue_id.gnb_du.ran_ue_id != NULL);
|
||||
*ue_id.gnb_du.ran_ue_id = rrc_ue_id;
|
||||
|
||||
return ue_id;
|
||||
}
|
||||
|
||||
ue_id_e2sm_t fill_e2sm_cucp_ue_id_data(const gNB_RRC_UE_t *rrc_ue_context, const uint32_t rrc_ue_id, const ue_id_t cucp_ue_id)
|
||||
{
|
||||
ue_id_e2sm_t ue_id = fill_e2sm_gnb_ue_id_data(rrc_ue_context, rrc_ue_id, cucp_ue_id);
|
||||
|
||||
//gNB-CU-CP UE E1AP ID List
|
||||
//C-ifCPUPseparated
|
||||
ue_id.gnb.gnb_cu_cp_ue_e1ap_lst_len = 1;
|
||||
ue_id.gnb.gnb_cu_cp_ue_e1ap_lst = calloc(ue_id.gnb.gnb_cu_cp_ue_e1ap_lst_len, sizeof(uint32_t));
|
||||
assert(ue_id.gnb.gnb_cu_cp_ue_e1ap_lst != NULL && "Memory exhausted");
|
||||
ue_id.gnb.gnb_cu_cp_ue_e1ap_lst[0] = rrc_ue_context->rrc_ue_id;
|
||||
|
||||
return ue_id;
|
||||
}
|
||||
|
||||
ue_id_e2sm_t fill_e2sm_cuup_ue_id_data(__attribute__((unused))const gNB_RRC_UE_t *rrc_ue_context, __attribute__((unused))const uint32_t rrc_ue_id, const ue_id_t cucp_ue_id)
|
||||
{
|
||||
ue_id_e2sm_t ue_id = {0};
|
||||
|
||||
ue_id.type = GNB_CU_UP_UE_ID_E2SM;
|
||||
|
||||
// 6.2.3.20
|
||||
// Mandatory
|
||||
ue_id.gnb_cu_up.gnb_cu_cp_ue_e1ap = cucp_ue_id; // RAN UE NGAP ID = gNB UE NGAP ID = rrc_ue_id
|
||||
|
||||
// 6.2.3.25
|
||||
// RAN UE ID
|
||||
// Optional
|
||||
ue_id.gnb_cu_up.ran_ue_id = calloc(1, sizeof(uint64_t));
|
||||
assert(ue_id.gnb_cu_up.ran_ue_id != NULL);
|
||||
*ue_id.gnb_cu_up.ran_ue_id = cucp_ue_id; // RAN UE NGAP ID = gNB UE NGAP ID = rrc_ue_id
|
||||
|
||||
return ue_id;
|
||||
}
|
||||
|
||||
get_ue_id fill_ue_id_data[END_NGRAN_NODE_TYPE] =
|
||||
{
|
||||
NULL,
|
||||
NULL,
|
||||
fill_e2sm_gnb_ue_id_data,
|
||||
NULL,
|
||||
NULL,
|
||||
fill_e2sm_cu_ue_id_data,
|
||||
NULL,
|
||||
fill_e2sm_du_ue_id_data,
|
||||
NULL,
|
||||
fill_e2sm_cucp_ue_id_data,
|
||||
fill_e2sm_cuup_ue_id_data,
|
||||
};
|
||||
42
openair2/E2AP/RAN_FUNCTION/O-RAN/ran_e2sm_ue_id.h
Normal file
42
openair2/E2AP/RAN_FUNCTION/O-RAN/ran_e2sm_ue_id.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef RAN_E2SM_UE_ID_H
|
||||
#define RAN_E2SM_UE_ID_H
|
||||
|
||||
#include "openair2/E2AP/flexric/src/agent/../sm/sm_io.h"
|
||||
#include "openair2/RRC/NR/rrc_gNB_UE_context.h"
|
||||
|
||||
ue_id_e2sm_t fill_e2sm_gnb_ue_id_data(const gNB_RRC_UE_t *rrc_ue_context, const uint32_t rrc_ue_id, const ue_id_t cucp_ue_id);
|
||||
|
||||
ue_id_e2sm_t fill_e2sm_cu_ue_id_data(const gNB_RRC_UE_t *rrc_ue_context, const uint32_t rrc_ue_id, const ue_id_t cucp_ue_id);
|
||||
|
||||
ue_id_e2sm_t fill_e2sm_du_ue_id_data(const gNB_RRC_UE_t *rrc_ue_context, const uint32_t rrc_ue_id, const ue_id_t cucp_ue_id);
|
||||
|
||||
ue_id_e2sm_t fill_e2sm_cucp_ue_id_data(const gNB_RRC_UE_t *rrc_ue_context, const uint32_t rrc_ue_id, const ue_id_t cucp_ue_id);
|
||||
|
||||
ue_id_e2sm_t fill_e2sm_cuup_ue_id_data(const gNB_RRC_UE_t *rrc_ue_context, const uint32_t rrc_ue_id, const ue_id_t cucp_ue_id);
|
||||
|
||||
typedef ue_id_e2sm_t (*get_ue_id)(const gNB_RRC_UE_t *rrc_ue_context, const uint32_t rrc_ue_id, const ue_id_t cucp_ue_id);
|
||||
|
||||
extern get_ue_id fill_ue_id_data[END_NGRAN_NODE_TYPE];
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
232
openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.c
Normal file
232
openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.c
Normal file
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "ran_func_kpm_subs.h"
|
||||
|
||||
#include <search.h>
|
||||
|
||||
/* measurements that need to store values from previous reporting period have a limitation
|
||||
when it comes to multiple subscriptions to the same UEs; ric_req_id is unique per subscription */
|
||||
typedef struct uldlcounter {
|
||||
uint32_t dl;
|
||||
uint32_t ul;
|
||||
} uldlcounter_t;
|
||||
|
||||
static uldlcounter_t last_pdcp_sdu_total_bytes[MAX_MOBILES_PER_GNB] = {0};
|
||||
|
||||
static nr_pdcp_statistics_t get_pdcp_stats_per_drb(const uint32_t rrc_ue_id, const int rb_id)
|
||||
{
|
||||
nr_pdcp_statistics_t pdcp = {0};
|
||||
const int srb_flag = 0;
|
||||
|
||||
// Get PDCP stats for specific DRB
|
||||
const bool rc = nr_pdcp_get_statistics(rrc_ue_id, srb_flag, rb_id, &pdcp);
|
||||
assert(rc == true && "Cannot get PDCP stats\n");
|
||||
|
||||
return pdcp;
|
||||
}
|
||||
|
||||
/* 3GPP TS 28.522 - section 5.1.2.1.1.1
|
||||
note: this measurement is calculated as per spec */
|
||||
static meas_record_lst_t fill_DRB_PdcpSduVolumeDL(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx)
|
||||
{
|
||||
meas_record_lst_t meas_record = {0};
|
||||
|
||||
// Get PDCP stats per DRB
|
||||
const int rb_id = 1; // at the moment, only 1 DRB is supported
|
||||
nr_pdcp_statistics_t pdcp = get_pdcp_stats_per_drb(ue_info.rrc_ue_id, rb_id);
|
||||
|
||||
meas_record.value = INTEGER_MEAS_VALUE;
|
||||
|
||||
// Get DL data volume delivered to PDCP layer
|
||||
meas_record.int_val = (pdcp.rxsdu_bytes - last_pdcp_sdu_total_bytes[ue_idx].dl)*8/1000; // [kb]
|
||||
last_pdcp_sdu_total_bytes[ue_idx].dl = pdcp.rxsdu_bytes;
|
||||
|
||||
return meas_record;
|
||||
}
|
||||
|
||||
/* 3GPP TS 28.522 - section 5.1.2.1.2.1
|
||||
note: this measurement is calculated as per spec */
|
||||
static meas_record_lst_t fill_DRB_PdcpSduVolumeUL(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx)
|
||||
{
|
||||
meas_record_lst_t meas_record = {0};
|
||||
|
||||
// Get PDCP stats per DRB
|
||||
const int rb_id = 1; // at the moment, only 1 DRB is supported
|
||||
nr_pdcp_statistics_t pdcp = get_pdcp_stats_per_drb(ue_info.rrc_ue_id, rb_id);
|
||||
|
||||
meas_record.value = INTEGER_MEAS_VALUE;
|
||||
|
||||
// Get UL data volume delivered from PDCP layer
|
||||
meas_record.int_val = (pdcp.txsdu_bytes - last_pdcp_sdu_total_bytes[ue_idx].ul)*8/1000; // [kb]
|
||||
last_pdcp_sdu_total_bytes[ue_idx].ul = pdcp.txsdu_bytes;
|
||||
|
||||
return meas_record;
|
||||
}
|
||||
|
||||
#if defined (NGRAN_GNB_DU)
|
||||
static uldlcounter_t last_rlc_pdu_total_bytes[MAX_MOBILES_PER_GNB] = {0};
|
||||
static uldlcounter_t last_total_prbs[MAX_MOBILES_PER_GNB] = {0};
|
||||
|
||||
static nr_rlc_statistics_t get_rlc_stats_per_drb(const rnti_t rnti, const int rb_id)
|
||||
{
|
||||
nr_rlc_statistics_t rlc = {0};
|
||||
const int srb_flag = 0;
|
||||
|
||||
// Get RLC stats for specific DRB
|
||||
const bool rc = nr_rlc_get_statistics(rnti, srb_flag, rb_id, &rlc);
|
||||
assert(rc == true && "Cannot get RLC stats\n");
|
||||
|
||||
// Activate average sojourn time at the RLC buffer for specific DRB
|
||||
nr_rlc_activate_avg_time_to_tx(rnti, rb_id+3, 1);
|
||||
|
||||
return rlc;
|
||||
}
|
||||
|
||||
/* 3GPP TS 28.522 - section 5.1.3.3.3
|
||||
note: by default this measurement is calculated for previous 100ms (openair2/LAYER2/nr_rlc/nr_rlc_entity.c:118, 173, 213); please, update according to your needs */
|
||||
static meas_record_lst_t fill_DRB_RlcSduDelayDl(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, __attribute__((unused))const size_t ue_idx)
|
||||
{
|
||||
meas_record_lst_t meas_record = {0};
|
||||
|
||||
// Get RLC stats per DRB
|
||||
const int rb_id = 1; // at the moment, only 1 DRB is supported
|
||||
nr_rlc_statistics_t rlc = get_rlc_stats_per_drb(ue_info.ue->rnti, rb_id);
|
||||
|
||||
meas_record.value = REAL_MEAS_VALUE;
|
||||
|
||||
// Get the value of sojourn time at the RLC buffer
|
||||
meas_record.real_val = rlc.txsdu_avg_time_to_tx; // [μs]
|
||||
|
||||
return meas_record;
|
||||
}
|
||||
|
||||
/* 3GPP TS 28.522 - section 5.1.1.3.1
|
||||
note: per spec, average UE throughput in DL (taken into consideration values from all UEs, and averaged)
|
||||
here calculated as: UE specific throughput in DL */
|
||||
static meas_record_lst_t fill_DRB_UEThpDl(uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx)
|
||||
{
|
||||
meas_record_lst_t meas_record = {0};
|
||||
|
||||
// Get RLC stats per DRB
|
||||
const int rb_id = 1; // at the moment, only 1 DRB is supported
|
||||
nr_rlc_statistics_t rlc = get_rlc_stats_per_drb(ue_info.ue->rnti, rb_id);
|
||||
meas_record.value = REAL_MEAS_VALUE;
|
||||
|
||||
// Calculate DL Thp
|
||||
meas_record.real_val = (double)(rlc.txpdu_bytes - last_rlc_pdu_total_bytes[ue_idx].dl)*8/gran_period_ms; // [kbps]
|
||||
last_rlc_pdu_total_bytes[ue_idx].dl = rlc.txpdu_bytes;
|
||||
|
||||
return meas_record;
|
||||
}
|
||||
|
||||
/* 3GPP TS 28.522 - section 5.1.1.3.3
|
||||
note: per spec, average UE throughput in UL (taken into consideration values from all UEs, and averaged)
|
||||
here calculated as: UE specific throughput in UL */
|
||||
static meas_record_lst_t fill_DRB_UEThpUl(uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx)
|
||||
{
|
||||
meas_record_lst_t meas_record = {0};
|
||||
|
||||
// Get RLC stats per DRB
|
||||
const int rb_id = 1; // at the moment, only 1 DRB is supported
|
||||
nr_rlc_statistics_t rlc = get_rlc_stats_per_drb(ue_info.ue->rnti, rb_id);
|
||||
|
||||
meas_record.value = REAL_MEAS_VALUE;
|
||||
|
||||
// Calculate UL Thp
|
||||
meas_record.real_val = (double)(rlc.rxpdu_bytes - last_rlc_pdu_total_bytes[ue_idx].ul)*8/gran_period_ms; // [kbps]
|
||||
last_rlc_pdu_total_bytes[ue_idx].ul = rlc.rxpdu_bytes;
|
||||
|
||||
return meas_record;
|
||||
}
|
||||
|
||||
/* 3GPP TS 28.522 - section 5.1.1.2.1
|
||||
note: per spec, DL PRB usage [%] = (total used PRBs for DL traffic / total available PRBs for DL traffic) * 100
|
||||
here calculated as: aggregated DL PRBs (t) - aggregated DL PRBs (t-gran_period) */
|
||||
static meas_record_lst_t fill_RRU_PrbTotDl(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx)
|
||||
{
|
||||
meas_record_lst_t meas_record = {0};
|
||||
|
||||
meas_record.value = INTEGER_MEAS_VALUE;
|
||||
|
||||
// Get the number of DL PRBs
|
||||
meas_record.int_val = ue_info.ue->mac_stats.dl.total_rbs - last_total_prbs[ue_idx].dl; // [PRBs]
|
||||
last_total_prbs[ue_idx].dl = ue_info.ue->mac_stats.dl.total_rbs;
|
||||
|
||||
return meas_record;
|
||||
}
|
||||
|
||||
/* 3GPP TS 28.522 - section 5.1.1.2.2
|
||||
note: per spec, UL PRB usage [%] = (total used PRBs for UL traffic / total available PRBs for UL traffic) * 100
|
||||
here calculated as: aggregated UL PRBs (t) - aggregated UL PRBs (t-gran_period) */
|
||||
static meas_record_lst_t fill_RRU_PrbTotUl(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx)
|
||||
{
|
||||
meas_record_lst_t meas_record = {0};
|
||||
|
||||
meas_record.value = INTEGER_MEAS_VALUE;
|
||||
|
||||
// Get the number of UL PRBs
|
||||
meas_record.int_val = ue_info.ue->mac_stats.ul.total_rbs - last_total_prbs[ue_idx].ul; // [PRBs]
|
||||
last_total_prbs[ue_idx].ul = ue_info.ue->mac_stats.ul.total_rbs;
|
||||
|
||||
return meas_record;
|
||||
}
|
||||
#endif
|
||||
|
||||
static kv_measure_t lst_measure[] = {
|
||||
{.key = "DRB.PdcpSduVolumeDL", .value = fill_DRB_PdcpSduVolumeDL },
|
||||
{.key = "DRB.PdcpSduVolumeUL", .value = fill_DRB_PdcpSduVolumeUL },
|
||||
#if defined (NGRAN_GNB_DU)
|
||||
{.key = "DRB.RlcSduDelayDl", .value = fill_DRB_RlcSduDelayDl },
|
||||
{.key = "DRB.UEThpDl", .value = fill_DRB_UEThpDl },
|
||||
{.key = "DRB.UEThpUl", .value = fill_DRB_UEThpUl },
|
||||
{.key = "RRU.PrbTotDl", .value = fill_RRU_PrbTotDl },
|
||||
{.key = "RRU.PrbTotUl", .value = fill_RRU_PrbTotUl },
|
||||
#endif
|
||||
};
|
||||
|
||||
ENTRY kv_pair;
|
||||
|
||||
void init_kpm_subs_data(void)
|
||||
{
|
||||
const size_t ht_len = sizeof(lst_measure) / sizeof(lst_measure[0]);
|
||||
hcreate(ht_len);
|
||||
|
||||
for (size_t i = 0; i < ht_len; i++) {
|
||||
kv_pair.key = lst_measure[i].key;
|
||||
kv_pair.data = &lst_measure[i];
|
||||
hsearch(kv_pair, ENTER);
|
||||
}
|
||||
}
|
||||
|
||||
meas_record_lst_t get_kpm_meas_value(char* kpm_meas_name, uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx)
|
||||
{
|
||||
assert(kpm_meas_name != NULL);
|
||||
|
||||
ENTRY search_entry = {.key = kpm_meas_name};
|
||||
ENTRY *found_entry = hsearch(search_entry, FIND);
|
||||
assert(found_entry != NULL && "Unsupported KPM measurement name");
|
||||
|
||||
kv_measure_t *kv_found = (kv_measure_t *)found_entry->data;
|
||||
meas_record_lst_t meas_record = kv_found->value(gran_period_ms, ue_info, ue_idx);
|
||||
|
||||
return meas_record;
|
||||
}
|
||||
49
openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.h
Normal file
49
openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef RAN_FUNC_SM_KPM_SUBSCRIPTION_AGENT_H
|
||||
#define RAN_FUNC_SM_KPM_SUBSCRIPTION_AGENT_H
|
||||
|
||||
#include "openair2/E2AP/flexric/src/sm/kpm_sm/kpm_data_ie_wrapper.h"
|
||||
|
||||
#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h"
|
||||
#include "openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h"
|
||||
#include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h"
|
||||
|
||||
typedef struct {
|
||||
uint32_t rrc_ue_id;
|
||||
NR_UE_info_t* ue;
|
||||
|
||||
} cudu_ue_info_pair_t;
|
||||
|
||||
typedef meas_record_lst_t (*kpm_meas_fp)(uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx);
|
||||
|
||||
typedef struct{
|
||||
char* key;
|
||||
kpm_meas_fp value;
|
||||
} kv_measure_t;
|
||||
|
||||
|
||||
void init_kpm_subs_data(void);
|
||||
|
||||
meas_record_lst_t get_kpm_meas_value(char* kpm_meas_name, uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx);
|
||||
|
||||
#endif
|
||||
@@ -22,10 +22,11 @@
|
||||
#include "ran_func_rc.h"
|
||||
#include "ran_func_rc_subs.h"
|
||||
#include "ran_func_rc_extern.h"
|
||||
#include "../../flexric/test/rnd/fill_rnd_data_rc.h" // this dependancy will be taken out once RAN Function Definition is implemented
|
||||
#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"
|
||||
#include "../../flexric/src/agent/e2_agent_api.h"
|
||||
#include "rc_ctrl_service_style_2.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
@@ -35,17 +36,440 @@ static pthread_once_t once_rc_mutex = PTHREAD_ONCE_INIT;
|
||||
static rc_subs_data_t rc_subs_data = {0};
|
||||
static pthread_mutex_t rc_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
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 void init_once_rc(void)
|
||||
{
|
||||
init_rc_subs_data(&rc_subs_data);
|
||||
}
|
||||
|
||||
static void fill_rc_ev_trig(ran_func_def_ev_trig_t* ev_trig)
|
||||
{
|
||||
// Sequence of EVENT TRIGGER styles
|
||||
// [1 - 63]
|
||||
ev_trig->sz_seq_ev_trg_style = 1;
|
||||
ev_trig->seq_ev_trg_style = calloc(ev_trig->sz_seq_ev_trg_style, sizeof(seq_ev_trg_style_t));
|
||||
assert(ev_trig->seq_ev_trg_style != NULL && "Memory exhausted");
|
||||
|
||||
seq_ev_trg_style_t* ev_trig_style = &ev_trig->seq_ev_trg_style[0];
|
||||
|
||||
// RIC Event Trigger Style Type
|
||||
// Mandatory
|
||||
// 9.3.3
|
||||
// 6.2.2.2.
|
||||
// INTEGER
|
||||
ev_trig_style->style = 4;
|
||||
|
||||
// RIC Event Trigger Style Name
|
||||
// Mandatory
|
||||
// 9.3.4
|
||||
// 6.2.2.3
|
||||
//PrintableString(SIZE(1..150,...))
|
||||
const char ev_style_name[] = "UE Information Change";
|
||||
ev_trig_style->name = cp_str_to_ba(ev_style_name);
|
||||
|
||||
// RIC Event Trigger Format Type
|
||||
// Mandatory
|
||||
// 9.3.5
|
||||
// 6.2.2.4.
|
||||
// INTEGER
|
||||
ev_trig_style->format = FORMAT_4_E2SM_RC_EV_TRIGGER_FORMAT;
|
||||
|
||||
// Sequence of RAN Parameters for L2 Variables
|
||||
// [0 - 65535]
|
||||
ev_trig->sz_seq_ran_param_l2_var = 0;
|
||||
ev_trig->seq_ran_param_l2_var = NULL;
|
||||
|
||||
//Sequence of Call Process Types
|
||||
// [0-65535]
|
||||
ev_trig->sz_seq_call_proc_type = 0;
|
||||
ev_trig->seq_call_proc_type = NULL;
|
||||
|
||||
// Sequence of RAN Parameters for Identifying UEs
|
||||
// 0-65535
|
||||
ev_trig->sz_seq_ran_param_id_ue = 0;
|
||||
ev_trig->seq_ran_param_id_ue = NULL;
|
||||
|
||||
// Sequence of RAN Parameters for Identifying Cells
|
||||
// 0-65535
|
||||
ev_trig->sz_seq_ran_param_id_cell = 0;
|
||||
ev_trig->seq_ran_param_id_cell = NULL;
|
||||
}
|
||||
|
||||
static void fill_rc_report(ran_func_def_report_t* report)
|
||||
{
|
||||
// Sequence of REPORT styles
|
||||
// [1 - 63]
|
||||
report->sz_seq_report_sty = 1;
|
||||
report->seq_report_sty = calloc(report->sz_seq_report_sty, sizeof(seq_report_sty_t));
|
||||
assert(report->seq_report_sty != NULL && "Memory exhausted");
|
||||
|
||||
seq_report_sty_t* report_style = &report->seq_report_sty[0];
|
||||
|
||||
// RIC Report Style Type
|
||||
// Mandatory
|
||||
// 9.3.3
|
||||
// 6.2.2.2.
|
||||
// INTEGER
|
||||
report_style->report_type = 4;
|
||||
|
||||
// RIC Report Style Name
|
||||
// Mandatory
|
||||
// 9.3.4
|
||||
// 6.2.2.3.
|
||||
// PrintableString(SIZE(1..150,...))
|
||||
const char report_name[] = "UE Information";
|
||||
report_style->name = cp_str_to_ba(report_name);
|
||||
|
||||
// Supported RIC Event Trigger Style Type
|
||||
// Mandatory
|
||||
// 9.3.3
|
||||
// 6.2.2.2.
|
||||
// INTEGER
|
||||
report_style->ev_trig_type = FORMAT_4_E2SM_RC_EV_TRIGGER_FORMAT;
|
||||
|
||||
// RIC Report Action Format Type
|
||||
// Mandatory
|
||||
// 9.3.5
|
||||
// 6.2.2.4.
|
||||
// INTEGER
|
||||
report_style->act_frmt_type = FORMAT_1_E2SM_RC_ACT_DEF;
|
||||
|
||||
// RIC Indication Header Format Type
|
||||
// Mandatory
|
||||
// 9.3.5
|
||||
// 6.2.2.4.
|
||||
// INTEGER
|
||||
report_style->ind_hdr_type = FORMAT_1_E2SM_RC_IND_HDR;
|
||||
|
||||
// RIC Indication Message Format Type
|
||||
// Mandatory
|
||||
// 9.3.5
|
||||
// 6.2.2.4.
|
||||
// INTEGER
|
||||
report_style->ind_msg_type = FORMAT_2_E2SM_RC_IND_MSG;
|
||||
|
||||
// Sequence of RAN Parameters Supported
|
||||
// [0 - 65535]
|
||||
report_style->sz_seq_ran_param = 1;
|
||||
report_style->ran_param = calloc(report_style->sz_seq_ran_param, sizeof(seq_ran_param_3_t));
|
||||
assert(report_style->ran_param != NULL && "Memory exhausted");
|
||||
|
||||
// RAN Parameter ID
|
||||
// Mandatory
|
||||
// 9.3.8
|
||||
// [1- 4294967295]
|
||||
report_style->ran_param[0].id = RRC_STATE_CHANGED_TO_E2SM_RC_RAN_PARAM_ID;
|
||||
|
||||
// RAN Parameter Name
|
||||
// Mandatory
|
||||
// 9.3.9
|
||||
// [1-150]
|
||||
const char ran_param_name[] = "RRC State";
|
||||
report_style->ran_param[0].name = cp_str_to_ba(ran_param_name);
|
||||
|
||||
// RAN Parameter Definition
|
||||
// Optional
|
||||
// 9.3.51
|
||||
report_style->ran_param[0].def = NULL;
|
||||
}
|
||||
|
||||
static void fill_rc_control(ran_func_def_ctrl_t* ctrl)
|
||||
{
|
||||
// Sequence of CONTROL styles
|
||||
// [1 - 63]
|
||||
ctrl->sz_seq_ctrl_style = 1;
|
||||
ctrl->seq_ctrl_style = calloc(ctrl->sz_seq_ctrl_style, sizeof(seq_ctrl_style_t));
|
||||
assert(ctrl->seq_ctrl_style != NULL && "Memory exhausted");
|
||||
|
||||
seq_ctrl_style_t* ctrl_style = &ctrl->seq_ctrl_style[0];
|
||||
|
||||
// RIC Control Style Type
|
||||
// Mandatory
|
||||
// 9.3.3
|
||||
// 6.2.2.2
|
||||
ctrl_style->style_type = 1;
|
||||
|
||||
//RIC Control Style Name
|
||||
//Mandatory
|
||||
//9.3.4
|
||||
// [1 -150]
|
||||
const char control_name[] = "Radio Bearer Control";
|
||||
ctrl_style->name = cp_str_to_ba(control_name);
|
||||
|
||||
// RIC Control Header Format Type
|
||||
// Mandatory
|
||||
// 9.3.5
|
||||
ctrl_style->hdr = FORMAT_1_E2SM_RC_CTRL_HDR;
|
||||
|
||||
// RIC Control Message Format Type
|
||||
// Mandatory
|
||||
// 9.3.5
|
||||
ctrl_style->msg = FORMAT_1_E2SM_RC_CTRL_MSG;
|
||||
|
||||
// RIC Call Process ID Format Type
|
||||
// Optional
|
||||
ctrl_style->call_proc_id_type = NULL;
|
||||
|
||||
// RIC Control Outcome Format Type
|
||||
// Mandatory
|
||||
// 9.3.5
|
||||
ctrl_style->out_frmt = FORMAT_1_E2SM_RC_CTRL_OUT;
|
||||
|
||||
// Sequence of Control Actions
|
||||
// [0-65535]
|
||||
ctrl_style->sz_seq_ctrl_act = 1;
|
||||
ctrl_style->seq_ctrl_act = calloc(ctrl_style->sz_seq_ctrl_act, sizeof(seq_ctrl_act_2_t));
|
||||
assert(ctrl_style->seq_ctrl_act != NULL && "Memory exhausted");
|
||||
|
||||
seq_ctrl_act_2_t* ctrl_act = &ctrl_style->seq_ctrl_act[0];
|
||||
|
||||
// Control Action ID
|
||||
// Mandatory
|
||||
// 9.3.6
|
||||
// [1-65535]
|
||||
ctrl_act->id = 2;
|
||||
|
||||
// Control Action Name
|
||||
// Mandatory
|
||||
// 9.3.7
|
||||
// [1-150]
|
||||
const char control_act_name[] = "QoS flow mapping configuration";
|
||||
ctrl_act->name = cp_str_to_ba(control_act_name);
|
||||
|
||||
// Sequence of Associated RAN Parameters
|
||||
// [0-65535]
|
||||
ctrl_act->sz_seq_assoc_ran_param = 2;
|
||||
ctrl_act->assoc_ran_param = calloc(ctrl_act->sz_seq_assoc_ran_param, sizeof(seq_ran_param_3_t));
|
||||
assert(ctrl_act->assoc_ran_param != NULL && "Memory exhausted");
|
||||
|
||||
seq_ran_param_3_t* assoc_ran_param = ctrl_act->assoc_ran_param;
|
||||
|
||||
// DRB ID
|
||||
assoc_ran_param[0].id = 1;
|
||||
const char ran_param_drb_id[] = "DRB ID";
|
||||
assoc_ran_param[0].name = cp_str_to_ba(ran_param_drb_id);
|
||||
assoc_ran_param[0].def = NULL;
|
||||
|
||||
// List of QoS Flows to be modified in DRB
|
||||
assoc_ran_param[1].id = 2;
|
||||
const char ran_param_list_qos_flow[] = "List of QoS Flows to be modified in DRB";
|
||||
assoc_ran_param[1].name = cp_str_to_ba(ran_param_list_qos_flow);
|
||||
assoc_ran_param[1].def = calloc(1, sizeof(ran_param_def_t));
|
||||
assert(assoc_ran_param[1].def != NULL && "Memory exhausted");
|
||||
|
||||
assoc_ran_param[1].def->type = LIST_RAN_PARAMETER_DEF_TYPE;
|
||||
assoc_ran_param[1].def->lst = calloc(1, sizeof(ran_param_type_t));
|
||||
assert(assoc_ran_param[1].def->lst != NULL && "Memory exhausted");
|
||||
|
||||
ran_param_type_t* lst = assoc_ran_param[1].def->lst;
|
||||
lst->sz_ran_param = 2;
|
||||
lst->ran_param = calloc(lst->sz_ran_param, sizeof(ran_param_lst_struct_t));
|
||||
assert(lst->ran_param != NULL && "Memory exhausted");
|
||||
|
||||
// QoS Flow Identifier
|
||||
lst->ran_param[0].ran_param_id = 4;
|
||||
const char ran_param_qos_flow_id[] = "QoS Flow Identifier";
|
||||
lst->ran_param[0].ran_param_name = cp_str_to_ba(ran_param_qos_flow_id);
|
||||
lst->ran_param[0].ran_param_def = NULL;
|
||||
|
||||
// QoS Flow Mapping Indication
|
||||
lst->ran_param[1].ran_param_id = 5;
|
||||
const char ran_param_qos_flow_mapping_ind[] = "QoS Flow Mapping Indication";
|
||||
lst->ran_param[1].ran_param_name = cp_str_to_ba(ran_param_qos_flow_mapping_ind);
|
||||
lst->ran_param[1].ran_param_def = NULL;
|
||||
|
||||
// Sequence of Associated RAN
|
||||
// Parameters for Control Outcome
|
||||
// [0- 255]
|
||||
ctrl_style->sz_ran_param_ctrl_out = 0;
|
||||
ctrl_style->ran_param_ctrl_out = NULL;
|
||||
}
|
||||
|
||||
e2sm_rc_func_def_t fill_rc_ran_def_gnb(void)
|
||||
{
|
||||
e2sm_rc_func_def_t def = {0};
|
||||
|
||||
// RAN Function Definition for EVENT TRIGGER
|
||||
// Optional
|
||||
// 9.2.2.2
|
||||
def.ev_trig = calloc(1, sizeof(ran_func_def_ev_trig_t));
|
||||
assert(def.ev_trig != NULL && "Memory exhausted");
|
||||
fill_rc_ev_trig(def.ev_trig);
|
||||
|
||||
// RAN Function Definition for REPORT
|
||||
// Optional
|
||||
// 9.2.2.3
|
||||
def.report = calloc(1, sizeof(ran_func_def_report_t));
|
||||
assert(def.report != NULL && "Memory exhausted");
|
||||
fill_rc_report(def.report);
|
||||
|
||||
// RAN Function Definition for INSERT
|
||||
// Optional
|
||||
// 9.2.2.4
|
||||
def.insert = NULL;
|
||||
|
||||
// RAN Function Definition for CONTROL
|
||||
// Optional
|
||||
// 9.2.2.5
|
||||
def.ctrl = calloc(1, sizeof(ran_func_def_ctrl_t));
|
||||
assert(def.ctrl != NULL && "Memory exhausted");
|
||||
fill_rc_control(def.ctrl);
|
||||
|
||||
// RAN Function Definition for POLICY
|
||||
// Optional
|
||||
// 9.2.2.6
|
||||
def.policy = NULL;
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
static e2sm_rc_func_def_t fill_rc_ran_def_cu(void)
|
||||
{
|
||||
e2sm_rc_func_def_t def = {0};
|
||||
|
||||
// RAN Function Definition for EVENT TRIGGER
|
||||
// Optional
|
||||
// 9.2.2.2
|
||||
def.ev_trig = calloc(1, sizeof(ran_func_def_ev_trig_t));
|
||||
assert(def.ev_trig != NULL && "Memory exhausted");
|
||||
fill_rc_ev_trig(def.ev_trig);
|
||||
|
||||
// RAN Function Definition for REPORT
|
||||
// Optional
|
||||
// 9.2.2.3
|
||||
def.report = calloc(1, sizeof(ran_func_def_report_t));
|
||||
assert(def.report != NULL && "Memory exhausted");
|
||||
fill_rc_report(def.report);
|
||||
|
||||
// RAN Function Definition for INSERT
|
||||
// Optional
|
||||
// 9.2.2.4
|
||||
def.insert = NULL;
|
||||
|
||||
// RAN Function Definition for CONTROL
|
||||
// Optional
|
||||
// 9.2.2.5
|
||||
def.ctrl = calloc(1, sizeof(ran_func_def_ctrl_t));
|
||||
assert(def.ctrl != NULL && "Memory exhausted");
|
||||
fill_rc_control(def.ctrl);
|
||||
|
||||
// RAN Function Definition for POLICY
|
||||
// Optional
|
||||
// 9.2.2.6
|
||||
def.policy = NULL;
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
static e2sm_rc_func_def_t fill_rc_ran_def_null(void)
|
||||
{
|
||||
e2sm_rc_func_def_t def = {0};
|
||||
|
||||
// RAN Function Definition for EVENT TRIGGER
|
||||
// Optional
|
||||
// 9.2.2.2
|
||||
def.ev_trig = NULL;
|
||||
|
||||
// RAN Function Definition for REPORT
|
||||
// Optional
|
||||
// 9.2.2.3
|
||||
def.report = NULL;
|
||||
|
||||
// RAN Function Definition for INSERT
|
||||
// Optional
|
||||
// 9.2.2.4
|
||||
def.insert = NULL;
|
||||
|
||||
// RAN Function Definition for CONTROL
|
||||
// Optional
|
||||
// 9.2.2.5
|
||||
def.ctrl = NULL;
|
||||
|
||||
// RAN Function Definition for POLICY
|
||||
// Optional
|
||||
// 9.2.2.6
|
||||
def.policy = NULL;
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
static e2sm_rc_func_def_t fill_rc_ran_def_cucp(void)
|
||||
{
|
||||
e2sm_rc_func_def_t def = {0};
|
||||
|
||||
// RAN Function Definition for EVENT TRIGGER
|
||||
// Optional
|
||||
// 9.2.2.2
|
||||
def.ev_trig = calloc(1, sizeof(ran_func_def_ev_trig_t));
|
||||
assert(def.ev_trig != NULL && "Memory exhausted");
|
||||
fill_rc_ev_trig(def.ev_trig);
|
||||
|
||||
// RAN Function Definition for REPORT
|
||||
// Optional
|
||||
// 9.2.2.3
|
||||
def.report = calloc(1, sizeof(ran_func_def_report_t));
|
||||
assert(def.report != NULL && "Memory exhausted");
|
||||
fill_rc_report(def.report);
|
||||
|
||||
// RAN Function Definition for INSERT
|
||||
// Optional
|
||||
// 9.2.2.4
|
||||
def.insert = NULL;
|
||||
|
||||
// RAN Function Definition for CONTROL
|
||||
// Optional
|
||||
// 9.2.2.5
|
||||
def.ctrl = NULL;
|
||||
|
||||
// RAN Function Definition for POLICY
|
||||
// Optional
|
||||
// 9.2.2.6
|
||||
def.policy = NULL;
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
typedef e2sm_rc_func_def_t (*fp_rc_func_def)(void);
|
||||
|
||||
static const fp_rc_func_def ran_def_rc[END_NGRAN_NODE_TYPE] =
|
||||
{
|
||||
NULL,
|
||||
NULL,
|
||||
fill_rc_ran_def_gnb,
|
||||
NULL,
|
||||
NULL,
|
||||
fill_rc_ran_def_cu,
|
||||
NULL,
|
||||
fill_rc_ran_def_null, // DU - at the moment, no Service is supported
|
||||
NULL,
|
||||
fill_rc_ran_def_cucp,
|
||||
fill_rc_ran_def_null, // CU-UP - at the moment, no Service is supported
|
||||
};
|
||||
|
||||
void read_rc_setup_sm(void* data)
|
||||
{
|
||||
assert(data != NULL);
|
||||
// assert(data->type == RAN_CTRL_V1_3_AGENT_IF_E2_SETUP_ANS_V0);
|
||||
rc_e2_setup_t* rc = (rc_e2_setup_t*)data;
|
||||
rc->ran_func_def = fill_rc_ran_func_def();
|
||||
|
||||
/* Fill the RAN Function Definition with currently supported measurements */
|
||||
|
||||
// RAN Function Name is already filled in fill_ran_function_name() in rc_sm_agent.c
|
||||
|
||||
const ngran_node_t node_type = get_e2_node_type();
|
||||
rc->ran_func_def = ran_def_rc[node_type]();
|
||||
|
||||
// E2 Setup Request is sent periodically until the connection is established
|
||||
// RC subscritpion data should be initialized only once
|
||||
@@ -56,53 +480,6 @@ void read_rc_setup_sm(void* data)
|
||||
|
||||
RB_PROTOTYPE(ric_id_2_param_id_trees, ric_req_id_s, entries, cmp_ric_req_id);
|
||||
|
||||
static ue_id_e2sm_t fill_ue_id_data(const gNB_RRC_UE_t *rrc_ue_context)
|
||||
{
|
||||
ue_id_e2sm_t ue_id = {0};
|
||||
|
||||
// Check the E2 node type
|
||||
#if defined (NGRAN_GNB_CUUP) && defined (NGRAN_GNB_CUCP)
|
||||
ue_id.type = GNB_UE_ID_E2SM;
|
||||
if (RC.nrrrc[0]->node_type == ngran_gNB_CU) {
|
||||
// gNB-CU UE F1AP ID List
|
||||
// C-ifCUDUseparated
|
||||
ue_id.gnb.gnb_cu_ue_f1ap_lst_len = 1;
|
||||
ue_id.gnb.gnb_cu_ue_f1ap_lst = calloc(ue_id.gnb.gnb_cu_ue_f1ap_lst_len, sizeof(uint32_t));
|
||||
assert(ue_id.gnb.gnb_cu_ue_f1ap_lst != NULL && "Memory exhausted");
|
||||
|
||||
for(size_t i = 0; i < ue_id.gnb.gnb_cu_ue_f1ap_lst_len; i++) {
|
||||
ue_id.gnb.gnb_cu_ue_f1ap_lst[i] = rrc_ue_context->rrc_ue_id;
|
||||
}
|
||||
} else if (RC.nrrrc[0]->node_type == ngran_gNB_CUCP) {
|
||||
//gNB-CU-CP UE E1AP ID List
|
||||
//C-ifCPUPseparated
|
||||
ue_id.gnb.gnb_cu_cp_ue_e1ap_lst_len = 1;
|
||||
ue_id.gnb.gnb_cu_cp_ue_e1ap_lst = calloc(ue_id.gnb.gnb_cu_cp_ue_e1ap_lst_len, sizeof(uint32_t));
|
||||
assert(ue_id.gnb.gnb_cu_cp_ue_e1ap_lst != NULL && "Memory exhausted");
|
||||
|
||||
for(size_t i = 0; i < ue_id.gnb.gnb_cu_cp_ue_e1ap_lst_len; i++) {
|
||||
ue_id.gnb.gnb_cu_cp_ue_e1ap_lst[i] = rrc_ue_context->rrc_ue_id;
|
||||
}
|
||||
} else if (RC.nrrrc[0]->node_type == ngran_gNB_DU) {
|
||||
assert(false && "RRC state change cannot be triggered from DU\n");
|
||||
}
|
||||
|
||||
#elif defined (NGRAN_GNB_CUUP)
|
||||
assert(false && "RRC state change cannot be triggered from CU-UP\n");
|
||||
|
||||
#endif
|
||||
|
||||
ue_id.gnb.amf_ue_ngap_id = rrc_ue_context->rrc_ue_id;
|
||||
ue_id.gnb.guami.amf_ptr = rrc_ue_context->ue_guami.amf_pointer;
|
||||
ue_id.gnb.guami.amf_region_id = rrc_ue_context->ue_guami.amf_region_id;
|
||||
ue_id.gnb.guami.amf_set_id = rrc_ue_context->ue_guami.amf_set_id;
|
||||
ue_id.gnb.guami.plmn_id.mcc = rrc_ue_context->ue_guami.mcc;
|
||||
ue_id.gnb.guami.plmn_id.mnc = rrc_ue_context->ue_guami.mnc;
|
||||
ue_id.gnb.guami.plmn_id.mnc_digit_len = rrc_ue_context->ue_guami.mnc_len;
|
||||
|
||||
return ue_id;
|
||||
}
|
||||
|
||||
static seq_ran_param_t fill_rrc_state_change_seq_ran(const rc_sm_rrc_state_e rrc_state)
|
||||
{
|
||||
seq_ran_param_t seq_ran_param = {0};
|
||||
@@ -112,7 +489,7 @@ static seq_ran_param_t fill_rrc_state_change_seq_ran(const rc_sm_rrc_state_e rrc
|
||||
seq_ran_param.ran_param_val.flag_false = calloc(1, sizeof(ran_parameter_value_t));
|
||||
assert(seq_ran_param.ran_param_val.flag_false != NULL && "Memory exhausted");
|
||||
seq_ran_param.ran_param_val.flag_false->type = INTEGER_RAN_PARAMETER_VALUE;
|
||||
seq_ran_param.ran_param_val.flag_false->int_ran = rrc_state;
|
||||
seq_ran_param.ran_param_val.flag_false->int_ran = rrc_state;
|
||||
|
||||
return seq_ran_param;
|
||||
}
|
||||
@@ -138,7 +515,8 @@ static rc_ind_data_t* fill_ue_rrc_state_change(const gNB_RRC_UE_t *rrc_ue_contex
|
||||
// UE ID
|
||||
// Mandatory
|
||||
// 9.3.10
|
||||
rc_ind->msg.frmt_2.seq_ue_id[0].ue_id = fill_ue_id_data(rrc_ue_context);
|
||||
const ngran_node_t node_type = get_e2_node_type();
|
||||
rc_ind->msg.frmt_2.seq_ue_id[0].ue_id = fill_ue_id_data[node_type](rrc_ue_context, 0, 0);
|
||||
|
||||
// Sequence of
|
||||
// RAN Parameter
|
||||
@@ -152,13 +530,13 @@ static rc_ind_data_t* fill_ue_rrc_state_change(const gNB_RRC_UE_t *rrc_ue_contex
|
||||
}
|
||||
|
||||
void signal_rrc_state_changed_to(const gNB_RRC_UE_t *rrc_ue_context, const rc_sm_rrc_state_e rrc_state)
|
||||
{
|
||||
{
|
||||
pthread_mutex_lock(&rc_mutex);
|
||||
if (rc_subs_data.rb[RRC_STATE_CHANGED_TO_E2SM_RC_RAN_PARAM_ID].rbh_root == NULL) {
|
||||
pthread_mutex_unlock(&rc_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
struct ric_req_id_s *node;
|
||||
RB_FOREACH(node, ric_id_2_param_id_trees, &rc_subs_data.rb[RRC_STATE_CHANGED_TO_E2SM_RC_RAN_PARAM_ID]) {
|
||||
rc_ind_data_t* rc_ind_data = fill_ue_rrc_state_change(rrc_ue_context, rrc_state);
|
||||
@@ -167,7 +545,7 @@ void signal_rrc_state_changed_to(const gNB_RRC_UE_t *rrc_ue_context, const rc_sm
|
||||
async_event_agent_api(node->ric_req_id, rc_ind_data);
|
||||
printf( "Event for RIC Req ID %u generated\n", node->ric_req_id);
|
||||
}
|
||||
|
||||
|
||||
pthread_mutex_unlock(&rc_mutex);
|
||||
}
|
||||
|
||||
@@ -196,13 +574,13 @@ sm_ag_if_ans_t write_subs_rc_sm(void const* src)
|
||||
arr_ran_param_id->ran_param_id = calloc(arr_ran_param_id->len, sizeof(ran_param_id_e));
|
||||
|
||||
const size_t sz = arr_ran_param_id->len;
|
||||
for(size_t i = 0; i < sz; i++) {
|
||||
for(size_t i = 0; i < sz; i++) {
|
||||
arr_ran_param_id->ran_param_id[i] = wr_rc->rc.ad->frmt_1.param_report_def[i].ran_param_id;
|
||||
}
|
||||
insert_rc_subs_data(&rc_subs_data, ric_req_id, arr_ran_param_id);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
AssertFatal(wr_rc->rc.ad->format == FORMAT_1_E2SM_RC_ACT_DEF, "Action Definition Format %d not yet implemented", wr_rc->rc.ad->format);
|
||||
}
|
||||
@@ -214,47 +592,75 @@ sm_ag_if_ans_t write_subs_rc_sm(void const* src)
|
||||
return ans;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
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");
|
||||
e2sm_rc_ctrl_msg_frmt_1_t const* frmt_1 = &ctrl->msg.frmt_1;
|
||||
for(size_t i = 0; i < frmt_1->sz_ran_param; ++i){
|
||||
seq_ran_param_t const* rp = frmt_1->ran_param;
|
||||
if(rp[i].ran_param_id == 1){
|
||||
assert(rp[i].ran_param_val.type == ELEMENT_KEY_FLAG_TRUE_RAN_PARAMETER_VAL_TYPE );
|
||||
printf("DRB ID %ld \n", rp[i].ran_param_val.flag_true->int_ran);
|
||||
} 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){
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
|
||||
int64_t qfi = lrp[j].ran_param_struct.ran_param_struct[0].ran_param_val.flag_true->int_ran;
|
||||
assert(qfi > -1 && qfi < 65);
|
||||
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");
|
||||
if(ctrl->hdr.frmt_1.ric_style_type == 1 && ctrl->hdr.frmt_1.ctrl_act_id == 2) {
|
||||
printf("QoS flow mapping configuration\n");
|
||||
|
||||
assert(lrp[j].ran_param_struct.ran_param_struct[1].ran_param_id == 5);
|
||||
assert(lrp[j].ran_param_struct.ran_param_struct[1].ran_param_val.type == ELEMENT_KEY_FLAG_FALSE_RAN_PARAMETER_VAL_TYPE);
|
||||
int64_t dir = lrp[j].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);
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
||||
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
|
||||
printf("qfi = %ld, dir %ld \n", qfi, dir);
|
||||
#ifdef NGRAN_GNB_DU
|
||||
} 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");
|
||||
}
|
||||
#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};
|
||||
ans.ctrl_out.type = RAN_CTRL_V1_3_AGENT_IF_CTRL_ANS_V0;
|
||||
return ans;
|
||||
|
||||
240
openair2/E2AP/RAN_FUNCTION/O-RAN/rc_ctrl_service_style_2.c
Normal file
240
openair2/E2AP/RAN_FUNCTION/O-RAN/rc_ctrl_service_style_2.c
Normal file
@@ -0,0 +1,240 @@
|
||||
#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"
|
||||
|
||||
static int add_mod_dl_slice(int mod_id,
|
||||
slice_algorithm_e current_algo,
|
||||
int 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_CAPACITY");
|
||||
float remain_pct = 1-((nvs_nr_slice_param_t *)dl->slices->s[0]->algo_data)->pct_reserved;
|
||||
nvs_params->pct_reserved = nvs_params->pct_reserved/100.0*remain_pct;
|
||||
} else {
|
||||
assert(0 != 0 && "Unknow current_algo");
|
||||
}
|
||||
|
||||
void *algo = &dl->dl_algo;
|
||||
char *l = NULL;
|
||||
if (label)
|
||||
l = strdup(label);
|
||||
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 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;
|
||||
}
|
||||
}
|
||||
|
||||
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 = cp_ba_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 = cp_ba_to_str(SST->ran_param_val.flag_false->octet_str_ran);
|
||||
char* rc_sd_str = cp_ba_to_str(SD->ran_param_val.flag_false->octet_str_ran);
|
||||
nssai_t RC_nssai = {.sst = atoi(rc_sst_str), .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_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) + 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 min_prb_ratio = 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, min_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_I(NR_MAC, "configure slice %ld, label %s, Dedicated_PRB_Policy_Ratio %ld\n", i, label_nssai, dedicated_prb_ratio);
|
||||
// TODO: could be extended to support max prb ratio in the MAC scheduling algorithm
|
||||
//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 /////
|
||||
/* Resource-based */
|
||||
void *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;
|
||||
const int rc = add_mod_dl_slice(mod_id, current_algo, i+1, RC_nssai, label_nssai, params);
|
||||
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;
|
||||
}
|
||||
/* TODO: Bandwidth-based */
|
||||
|
||||
/// 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;
|
||||
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_nssai.sst, &RC_nssai.sd)) {
|
||||
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_nssai.sst, RC_nssai.sd);
|
||||
|
||||
if (UE_mcc == RC_mcc && UE_mnc == RC_mnc && UE_sst == RC_nssai.sst && UE_sd == RC_nssai.sd) {
|
||||
dl->add_UE(dl->slices, UE);
|
||||
} 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_nssai.sst, RC_nssai.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;
|
||||
}
|
||||
36
openair2/E2AP/RAN_FUNCTION/O-RAN/rc_ctrl_service_style_2.h
Normal file
36
openair2/E2AP/RAN_FUNCTION/O-RAN/rc_ctrl_service_style_2.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifndef OPENAIRINTERFACE_RC_CTRL_SERVICE_STYLE_2_H
|
||||
#define OPENAIRINTERFACE_RC_CTRL_SERVICE_STYLE_2_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"
|
||||
|
||||
bool add_mod_rc_slice(int mod_id, size_t slices_len, ran_param_list_t* lst);
|
||||
|
||||
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
|
||||
@@ -21,10 +21,109 @@
|
||||
|
||||
#include "read_setup_ran.h"
|
||||
#include "../../E2AP/flexric/src/lib/e2ap/e2ap_node_component_config_add_wrapper.h"
|
||||
#include "../../E2AP/flexric/test/rnd/fill_rnd_data_e2_setup_req.h"
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(E2AP_V2) || defined(E2AP_V3)
|
||||
// NGAP
|
||||
static e2ap_node_component_config_add_t fill_ngap_e2ap_node_component_config_add(void)
|
||||
{
|
||||
e2ap_node_component_config_add_t dst = {0};
|
||||
|
||||
// Mandatory
|
||||
// 9.2.26
|
||||
dst.e2_node_comp_interface_type = NG_E2AP_NODE_COMP_INTERFACE_TYPE;
|
||||
// Bug!! Optional in the standard, mandatory in ASN.1
|
||||
// 9.2.32
|
||||
dst.e2_node_comp_id.type = NG_E2AP_NODE_COMP_INTERFACE_TYPE;
|
||||
|
||||
const char ng_msg[] = "Dummy message";
|
||||
dst.e2_node_comp_id.ng_amf_name = cp_str_to_ba(ng_msg);
|
||||
|
||||
// Mandatory
|
||||
// 9.2.27
|
||||
const char req[] = "NGAP Request Message sent";
|
||||
const char res[] = "NGAP Response Message reveived";
|
||||
|
||||
dst.e2_node_comp_conf.request = cp_str_to_ba(req);
|
||||
dst.e2_node_comp_conf.response = cp_str_to_ba(res);
|
||||
return dst;
|
||||
}
|
||||
|
||||
// F1AP
|
||||
static e2ap_node_component_config_add_t fill_f1ap_e2ap_node_component_config_add(void)
|
||||
{
|
||||
e2ap_node_component_config_add_t dst = {0};
|
||||
|
||||
// Mandatory
|
||||
// 9.2.26
|
||||
dst.e2_node_comp_interface_type = F1_E2AP_NODE_COMP_INTERFACE_TYPE;
|
||||
// Bug!! Optional in the standard, mandatory in ASN.1
|
||||
// 9.2.32
|
||||
dst.e2_node_comp_id.type = F1_E2AP_NODE_COMP_INTERFACE_TYPE;
|
||||
|
||||
dst.e2_node_comp_id.f1_gnb_du_id = 1023;
|
||||
|
||||
// Mandatory
|
||||
// 9.2.27
|
||||
const char req[] = "F1AP Request Message sent";
|
||||
const char res[] = "F1AP Response Message reveived";
|
||||
|
||||
dst.e2_node_comp_conf.request = cp_str_to_ba(req);
|
||||
dst.e2_node_comp_conf.response = cp_str_to_ba(res);
|
||||
return dst;
|
||||
}
|
||||
|
||||
// E1AP
|
||||
static e2ap_node_component_config_add_t fill_e1ap_e2ap_node_component_config_add(void)
|
||||
{
|
||||
e2ap_node_component_config_add_t dst = {0};
|
||||
|
||||
// Mandatory
|
||||
// 9.2.26
|
||||
dst.e2_node_comp_interface_type = E1_E2AP_NODE_COMP_INTERFACE_TYPE;
|
||||
// Bug!! Optional in the standard, mandatory in ASN.1
|
||||
// 9.2.32
|
||||
dst.e2_node_comp_id.type = E1_E2AP_NODE_COMP_INTERFACE_TYPE;
|
||||
|
||||
dst.e2_node_comp_id.e1_gnb_cu_up_id = 1025;
|
||||
|
||||
// Mandatory
|
||||
// 9.2.27
|
||||
const char req[] = "E1AP Request Message sent";
|
||||
const char res[] = "E1AP Response Message reveived";
|
||||
|
||||
dst.e2_node_comp_conf.request = cp_str_to_ba(req);
|
||||
dst.e2_node_comp_conf.response = cp_str_to_ba(res);
|
||||
return dst;
|
||||
}
|
||||
|
||||
// S1AP
|
||||
static e2ap_node_component_config_add_t fill_s1ap_e2ap_node_component_config_add(void)
|
||||
{
|
||||
e2ap_node_component_config_add_t dst = {0};
|
||||
|
||||
// Mandatory
|
||||
// 9.2.26
|
||||
dst.e2_node_comp_interface_type = S1_E2AP_NODE_COMP_INTERFACE_TYPE;
|
||||
// Bug!! Optional in the standard, mandatory in ASN.1
|
||||
// 9.2.32
|
||||
dst.e2_node_comp_id.type = S1_E2AP_NODE_COMP_INTERFACE_TYPE;
|
||||
|
||||
const char str[] = "S1 NAME";
|
||||
dst.e2_node_comp_id.s1_mme_name = cp_str_to_ba(str);
|
||||
|
||||
// Mandatory
|
||||
// 9.2.27
|
||||
const char req[] = "S1AP Request Message sent";
|
||||
const char res[] = "S1AP Response Message reveived";
|
||||
|
||||
dst.e2_node_comp_conf.request = cp_str_to_ba(req);
|
||||
dst.e2_node_comp_conf.response = cp_str_to_ba(res);
|
||||
return dst;
|
||||
}
|
||||
#endif
|
||||
|
||||
void read_setup_ran(void* data, const ngran_node_t node_type)
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
@@ -13,6 +13,8 @@ Please see [NOTICE](NOTICE.md) file for third party software that is included in
|
||||
|
||||
This tutorial describes the steps of deployment 5G OAI RAN, with integrated E2 agent and a nearRT-RIC using O-RAN compliant FlexRIC.
|
||||
|
||||
[[_TOC_]]
|
||||
|
||||
# 1. Installation
|
||||
|
||||
## 1.1 Install prerequisites
|
||||
@@ -21,7 +23,7 @@ This tutorial describes the steps of deployment 5G OAI RAN, with integrated E2 a
|
||||
|
||||
On Ubuntu, you might want to use [this PPA](https://apt.kitware.com/) to install an up-to-date version.
|
||||
|
||||
- SWIG (at least v.4.0).
|
||||
- SWIG (at least v.4.1).
|
||||
|
||||
We use SWIG as an interface generator to enable the multi-language feature (i.e., C/C++ and Python) for the xApps. Please, check your SWIG version (i.e, `swig
|
||||
-version`) and install it from scratch if necessary as described here: https://swig.org/svn.html or via the code below:
|
||||
@@ -69,17 +71,11 @@ Currently available versions:
|
||||
| E2AP v2.03 | Y | Y |
|
||||
| E2AP v3.01 | Y | Y |
|
||||
|
||||
Please note that KPM SM v2.01 is supported only in FlexRIC, but not in OAI.
|
||||
Please note that KPM SM v2.01 is supported only in FlexRIC, but not in OAI.
|
||||
|
||||
```bash
|
||||
cd cmake_targets/
|
||||
./build_oai -I -w SIMU --gNB --nrUE --build-e2 --ninja
|
||||
```
|
||||
If the openair2/E2AP/flexric folder is empty, try manually the following commands
|
||||
|
||||
```bash
|
||||
git submodule init
|
||||
git submodule update
|
||||
```
|
||||
|
||||
* `-I` option is to install pre-requisites, you only need it the first time you build the softmodem or when some oai dependencies have changed.
|
||||
@@ -89,16 +85,22 @@ git submodule update
|
||||
* `--ninja` is to use the ninja build tool, which speeds up compilation
|
||||
* `--build-e2` option is to use the E2 agent, integrated within RAN.
|
||||
|
||||
If the openair2/E2AP/flexric folder is empty, try manually the following commands:
|
||||
```bash
|
||||
git submodule init
|
||||
git submodule update
|
||||
```
|
||||
|
||||
## 2.2 FlexRIC
|
||||
|
||||
- By default, FlexRIC will build the nearRT-RIC with E2AP v2 and KPM v2. If you want a different version, edit the variable E2AP\_VERSION and KPM\_VERSION at FlexRIC's CMakeLists.txt file. Note that OAI's and FlexRIC's E2AP\_VERSION and KPM\_VERSION need to match due to O-RAN incompatibilities among versions.
|
||||
By default, FlexRIC will build the nearRT-RIC with E2AP v2 and KPM v2. If you want a different version, edit the variable E2AP\_VERSION and KPM\_VERSION at FlexRIC's CMakeLists.txt file. Note that OAI's and FlexRIC's E2AP\_VERSION and KPM\_VERSION need to match due to O-RAN incompatibilities among versions.
|
||||
|
||||
|
||||
### 2.2.1 Clone the FlexRIC repository
|
||||
```bash
|
||||
git clone https://gitlab.eurecom.fr/mosaic5g/flexric flexric
|
||||
cd flexric/
|
||||
git checkout 29af8408afad3da36824bd7912562202023ae924
|
||||
git checkout 07e8f8f198b72a0c9b39cc6ed6d0dbce6af133f8
|
||||
```
|
||||
|
||||
### 2.2.2 Build FlexRIC
|
||||
@@ -113,27 +115,47 @@ sudo make install
|
||||
|
||||
By default the service model libraries will be installed in the path `/usr/local/lib/flexric` while the configuration file in `/usr/local/etc/flexric`.
|
||||
|
||||
#### 2.2.3.1 Available Service Models
|
||||
1. KPM v02.03 and KPM v03.00 (`xapp_kpm_moni`)
|
||||
At the moment, the following measurements are supported in OAI RAN:
|
||||
* "DRB.PdcpSduVolumeDL"
|
||||
* "DRB.PdcpSduVolumeUL"
|
||||
* "DRB.RlcSduDelayDl"
|
||||
* "DRB.UEThpDl"
|
||||
* "DRB.UEThpUl"
|
||||
* "RRU.PrbTotDl"
|
||||
* "RRU.PrbTotUl"
|
||||
# 3. Service Models available in OAI RAN
|
||||
|
||||
2. RC v01.03
|
||||
Currently available RC xApps:
|
||||
* `xapp_kpm_rc` - RAN control function "QoS flow mapping configuration" support, i.e. creating a new DRB.
|
||||
* `xapp_rc_moni` - aperiodic subscription support for "UE RRC State Change"
|
||||
## 3.1 O-RAN
|
||||
|
||||
3. MAC + RLC + PDCP + GTP (`xapp_gtp_mac_rlc_pdcp_moni`)
|
||||
We assume that user is familiar with O-RAN WG3 specifications that can be found at https://orandownloadsweb.azurewebsites.net/specifications.
|
||||
|
||||
### 3.1.1 E2SM-KPM
|
||||
|
||||
As mentioned in section [2.1.2 Build OAI with E2 Agent](#212-build-oai-with-e2-agent), we support KPM v2.03/v3.00. Uses ASN.1 encoding.
|
||||
|
||||
Per O-RAN specifications, 5G measurements supported by KPM are specified in 3GPP TS 28.552.
|
||||
|
||||
From 3GPP TS 28.552, we support the following list:
|
||||
* "DRB.PdcpSduVolumeDL"
|
||||
* "DRB.PdcpSduVolumeUL"
|
||||
* "DRB.RlcSduDelayDl"
|
||||
* "DRB.UEThpDl"
|
||||
* "DRB.UEThpUl"
|
||||
* "RRU.PrbTotDl"
|
||||
* "RRU.PrbTotUl"
|
||||
|
||||
From O-RAN.WG3.E2SM-KPM-version specification, we implemented:
|
||||
* REPORT Service Style 4 ("Common condition-based, UE-level" - section 7.4.5) - fetch above measurements per each UE that matches common criteria (e.g. S-NSSAI).
|
||||
|
||||
### 3.1.2 E2SM-RC
|
||||
|
||||
We support RC v1.03. Uses ASN.1 encoding.
|
||||
|
||||
From ORAN.WG3.E2SM-RC-v01.03 specification, we implemented:
|
||||
* REPORT Service Style 4 ("UE Information" - section 7.4.5) - aperiodic subscription for "UE RRC State Change"
|
||||
* CONTROL Service Style 1 ("Radio Bearer Control" - section 7.6.2) - "QoS flow mapping configuration" (e.g creating a new DRB)
|
||||
|
||||
## 3.2 Custom Service Models
|
||||
|
||||
In addition, we support custom Service Models, such are MAC, RLC, PDCP, and GTP. Use plain encoding.
|
||||
|
||||
If you are interested in TC and SLICE SMs, please follow the instructions at https://gitlab.eurecom.fr/mosaic5g/flexric.
|
||||
|
||||
# 3. Start the process
|
||||
# 4. Start the process
|
||||
|
||||
At this point, we assume the 5G Core Network is already running in backgroud. For more information, please take a look at
|
||||
|
||||
In order to configure E2 agent, please, add the following block in OAI's configuration file:
|
||||
```bash
|
||||
@@ -142,61 +164,75 @@ e2_agent = {
|
||||
sm_dir = "/usr/local/lib/flexric/"
|
||||
}
|
||||
```
|
||||
* start E2 Node agents
|
||||
|
||||
* start the gNB-mono
|
||||
```bash
|
||||
cd oai/cmake_targets/ran_build/build
|
||||
sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --rfsim --sa -E
|
||||
```
|
||||
As per O-RAN.WG3.E2SM-v02.00 specifications, UE ID (section 6.2.2.6) representation in OAI is:
|
||||
| | gNB-mono | CU | CU-CP | CU-UP | DU |
|
||||
|:----------------------|:----------------|:----------------|:----------------|:----------------------|:-------------------|
|
||||
| CHOICE UE ID case | GNB_UE_ID_E2SM | GNB_UE_ID_E2SM | GNB_UE_ID_E2SM | GNB_CU_UP_UE_ID_E2SM | GNB_DU_UE_ID_E2SM |
|
||||
| AMF UE NGAP ID | amf_ue_ngap_id | amf_ue_ngap_id | amf_ue_ngap_id | | |
|
||||
| GUAMI | guami | guami | guami | | |
|
||||
| gNB-CU UE F1AP ID | | rrc_ue_id | | | rrc_ue_id |
|
||||
| gNB-CU-CP UE E1AP ID | | | rrc_ue_id | rrc_ue_id | |
|
||||
| RAN UE ID | rrc_ue_id | rrc_ue_id | rrc_ue_id | rrc_ue_id | rrc_ue_id |
|
||||
|
||||
* if CU/DU split is used, start the gNB as follows
|
||||
```bash
|
||||
sudo ./nr-softmodem -O <path_to_du_conf_file> --rfsim --sa -E
|
||||
sudo ./nr-softmodem -O <path_to_cu_conf_file> --sa
|
||||
```
|
||||
* start the gNB-mono
|
||||
```bash
|
||||
cd oai/cmake_targets/ran_build/build
|
||||
sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --rfsim --sa -E
|
||||
```
|
||||
|
||||
* if CU-CP/CU-UP/DU split is used, start the gNB as follows
|
||||
```bash
|
||||
sudo ./nr-softmodem -O <path_to_du_conf_file> --rfsim --sa -E
|
||||
sudo ./nr-softmodem -O <path_to_cu_cp_conf_file> --sa
|
||||
sudo ./nr-cuup -O <path_to_cu_up_conf_file> --sa
|
||||
```
|
||||
* if CU/DU split is used, start the gNB as follows
|
||||
```bash
|
||||
sudo ./nr-softmodem -O <path_to_du_conf_file> --rfsim --sa -E
|
||||
sudo ./nr-softmodem -O <path_to_cu_conf_file> --sa
|
||||
```
|
||||
|
||||
* if CU-CP/CU-UP/DU split is used, start the gNB as follows
|
||||
```bash
|
||||
sudo ./nr-softmodem -O <path_to_du_conf_file> --rfsim --sa -E
|
||||
sudo ./nr-softmodem -O <path_to_cu_cp_conf_file> --sa
|
||||
sudo ./nr-cuup -O <path_to_cu_up_conf_file> --sa
|
||||
```
|
||||
|
||||
* start the nrUE
|
||||
```bash
|
||||
cd oai/cmake_targets/ran_build/build
|
||||
sudo ./nr-uesoftmodem -r 106 --numerology 1 --band 78 -C 3619200000 --rfsim --sa --uicc0.imsi 001010000000001 --rfsimulator.serveraddr 127.0.0.1
|
||||
```
|
||||
```bash
|
||||
cd oai/cmake_targets/ran_build/build
|
||||
sudo ./nr-uesoftmodem -r 106 --numerology 1 --band 78 -C 3619200000 --rfsim --sa --uicc0.imsi 001010000000001 --rfsimulator.serveraddr 127.0.0.1
|
||||
```
|
||||
|
||||
* start the nearRT-RIC
|
||||
```bash
|
||||
cd flexric
|
||||
./build/examples/ric/nearRT-RIC
|
||||
```
|
||||
```bash
|
||||
cd flexric
|
||||
./build/examples/ric/nearRT-RIC
|
||||
```
|
||||
|
||||
* start the KPM monitor xApp
|
||||
```bash
|
||||
cd flexric
|
||||
./build/examples/xApp/c/monitor/xapp_kpm_moni
|
||||
```
|
||||
* Start different xApps
|
||||
|
||||
* start the RC monitor xApp
|
||||
```bash
|
||||
cd flexric
|
||||
./build/examples/xApp/c/monitor/xapp_rc_moni
|
||||
```
|
||||
* start the KPM monitor xApp - measurements stated in [3.1.1 E2SM-KPM](#311-e2sm-kpm) for each UE that matches S-NSSAI common criteria
|
||||
```bash
|
||||
cd flexric
|
||||
./build/examples/xApp/c/monitor/xapp_kpm_moni
|
||||
```
|
||||
Note: we assume that each UE has only 1 DRB; CU-UP does not store the slices, therefore "coarse filtering" is used
|
||||
|
||||
* start the RC control xApp
|
||||
```bash
|
||||
cd flexric
|
||||
./build/examples/xApp/c/kpm_rc/xapp_kpm_rc
|
||||
```
|
||||
* start the RC monitor xApp - aperiodic subscription for "UE RRC State Change"
|
||||
```bash
|
||||
cd flexric
|
||||
./build/examples/xApp/c/monitor/xapp_rc_moni
|
||||
```
|
||||
|
||||
* start the (MAC + RLC + PDCP + GTP) monitor xApp
|
||||
```bash
|
||||
cd flexric
|
||||
./build/examples/xApp/c/monitor/xapp_gtp_mac_rlc_pdcp_moni
|
||||
```
|
||||
* start the RC control xApp - RAN control function "QoS flow mapping configuration" (e.g. creating a new DRB)
|
||||
```bash
|
||||
cd flexric
|
||||
./build/examples/xApp/c/kpm_rc/xapp_kpm_rc
|
||||
```
|
||||
|
||||
* start the (MAC + RLC + PDCP + GTP) monitor xApp
|
||||
```bash
|
||||
cd flexric
|
||||
./build/examples/xApp/c/monitor/xapp_gtp_mac_rlc_pdcp_moni
|
||||
```
|
||||
The latency that you observe in your monitor xApp is the latency from the E2 Agent to the nearRT-RIC and xApp.
|
||||
Therefore, FlexRIC is well suited for use cases with ultra low-latency requirements.
|
||||
Additionally, all the data received in the `xapp_gtp_mac_rlc_pdcp_moni` xApp is also written to /tmp/xapp_db in case that offline data processing is wanted (e.g., Machine Learning/Artificial Intelligence applications). You can browse the data using e.g., sqlitebrowser.
|
||||
|
||||
Submodule openair2/E2AP/flexric updated: 7c424e882a...34d6810f9a
@@ -878,7 +878,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);
|
||||
|
||||
@@ -319,8 +319,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
|
||||
@@ -347,20 +350,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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -587,13 +592,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;
|
||||
@@ -654,7 +676,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 */
|
||||
@@ -807,7 +829,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,
|
||||
@@ -824,7 +846,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)
|
||||
{
|
||||
@@ -876,16 +906,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
|
||||
@@ -910,7 +941,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,
|
||||
@@ -928,7 +964,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;
|
||||
@@ -1266,10 +1305,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;
|
||||
@@ -1321,6 +1361,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 */
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
|
||||
#include "common/ran_context.h"
|
||||
#include "nfapi/oai_integration/vendor_ext.h"
|
||||
#include "NR_MAC_gNB/slicing/nr_slicing.h"
|
||||
|
||||
//#define DEBUG_DCI
|
||||
|
||||
@@ -1874,6 +1875,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
|
||||
*/
|
||||
@@ -2049,6 +2074,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);
|
||||
}
|
||||
@@ -2461,6 +2490,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++) {
|
||||
@@ -2600,6 +2639,14 @@ void mac_remove_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rnti)
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
NR_UE_info_t * newUEs[MAX_MOBILES_PER_GNB+1]={0};
|
||||
int newListIdx=0;
|
||||
for (int i=0; i<MAX_MOBILES_PER_GNB; i++)
|
||||
@@ -3071,6 +3118,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);
|
||||
|
||||
|
||||
@@ -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,
|
||||
@@ -179,7 +179,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);
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "openair2/F1AP/f1ap_ids.h"
|
||||
#include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h"
|
||||
#include "F1AP_CauseRadioNetwork.h"
|
||||
#include "NR_MAC_gNB/slicing/nr_slicing.h"
|
||||
|
||||
#include "uper_decoder.h"
|
||||
#include "uper_encoder.h"
|
||||
@@ -237,8 +238,28 @@ NR_CellGroupConfig_t *clone_CellGroupConfig(const NR_CellGroupConfig_t *orig)
|
||||
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;
|
||||
} else {
|
||||
nssai_t nssai = {.sst = 0, .sd = 0};
|
||||
sched_ctrl->dl_lc_nssai[lcid] = nssai;
|
||||
}
|
||||
LOG_I(NR_MAC, "Setting NSSAI sst: %d, sd: %d for SRB: %ld\n", sched_ctrl->dl_lc_nssai[lcid].sst, sched_ctrl->dl_lc_nssai[lcid].sd, srb->srb_id);
|
||||
}
|
||||
|
||||
for (int i = 0; i < drb_len; i++) {
|
||||
const f1ap_drb_to_be_setup_t *drb = &req_drbs[i];
|
||||
|
||||
@@ -360,8 +381,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 */
|
||||
@@ -465,7 +494,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
|
||||
}
|
||||
|
||||
@@ -259,7 +259,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);
|
||||
|
||||
@@ -110,6 +110,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,
|
||||
@@ -534,6 +536,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 {
|
||||
@@ -634,6 +644,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;
|
||||
@@ -707,6 +724,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 {
|
||||
@@ -721,6 +740,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);
|
||||
@@ -728,6 +760,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;
|
||||
@@ -826,7 +896,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;
|
||||
|
||||
|
||||
112
openair2/LAYER2/NR_MAC_gNB/slicing/README.md
Normal file
112
openair2/LAYER2/NR_MAC_gNB/slicing/README.md
Normal file
@@ -0,0 +1,112 @@
|
||||
# Slicing in NR MAC Scheduler
|
||||
|
||||
`nr_schedule_ue_spec()` is divided into two parts:
|
||||
1. **Pre-processor** makes the scheduling decisions by **slice-** and **user-** levels scheduling [1] [2]
|
||||
2. **Post-processor** fills the scheduling decisions into nFAPI structures to indicate to the PHY
|
||||
|
||||
The pre-processor is defined by the structure `nr_pp_impl_param_dl_t` and
|
||||
it is initialized by `nr_init_fr1_dlsch_preprocessor()` in `mac_top_init_gNB()`:
|
||||
```c
|
||||
RC.nrmac[i]->pre_processor_dl = nr_init_fr1_dlsch_preprocessor(0);
|
||||
```
|
||||
|
||||
In addition, the algorithm for slice-level scheduler
|
||||
is defined by the structure `nr_pp_impl_dl` and
|
||||
is assigned by the function pointer `nr_fr1_dlsch_preprocessor()` by default, which is _none_ slicing algorithm (means there is no slices in the system to be scheduled).
|
||||
On the other hand, the algorithm for user-level scheduler
|
||||
is defined by the structure `nr_dl_sched_algo_t` and
|
||||
is assigned by the structure pointer `nr_proportional_fair_wbcqi_dl` by default, which is adopting _proportional fair_ algorithm (`nr_pf_dl()`) to schedule the UEs.
|
||||
Both schedulers are initialized in `nr_init_fr1_dlsch_preprocessor()`:
|
||||
```c
|
||||
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;
|
||||
```
|
||||
|
||||
## Slice-level Scheduler
|
||||
The slice-level scheduler in pre-preprocessor is enabled by calling
|
||||
`gNB_mac->pre_processor_dl.dl()` in `nr_schedule_ue_spec()`.
|
||||
|
||||
Through Near-Real-Time RIC, xApp and RAN Control (RC) service model,
|
||||
the slice-level scheduler can be customized to other algorithm on-the-fly.
|
||||
> For an example,NVS [3] algorithm is implemented in the `nr_slicing.c`,
|
||||
and it is initialized through `set_new_dl_slice_algo()` in the RC RAN function `E2AP/RAN_FUNCTION/rc_ran_func.c`:
|
||||
> ```c
|
||||
> 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);
|
||||
> nrmac->pre_processor_dl.slices = NULL;
|
||||
> break;
|
||||
> }
|
||||
> ```
|
||||
> In `nvs_nr_dl_init()`, the slice-level scheduler is changed to point to the function `nvs_nr_dl()`,
|
||||
which will be called by `gNB_mac->pre_processor_dl.dl()` in the pre-processor to schedule the slices based on the NVS algorithm.
|
||||
|
||||
To implement different slice-level scheduling algorithm,
|
||||
you can start from `nr_slicing.h` by adding the parameters related to your scheduling algorithm
|
||||
and init function (e.g., `nvs_nr_dl_init()`).
|
||||
Afterwards, you can start create the corresponding functions which are used in your init function,
|
||||
> take an example in `nvs_nr_dl_init()`, these are the required functions need to be implemented:
|
||||
> - `nvs_nr_dl()` is the function for your slice-level scheduling algorithm (i.e, select a slice, or sort slices)
|
||||
> - `addmod_nvs_nr_slice_dl()` is the function to add or modify the setting/configuration of existing slices (i.e., increase the capacity, change user-level scheduling algorithm)
|
||||
> - `remove_nvs_nr_slice_dl()` is the function to remove the slice from the existing slices
|
||||
> - `nvs_nr_destroy()` is the function to delete all the slices in the system
|
||||
|
||||
|
||||
## User-level Scheduler
|
||||
The user-level scheduler in pre-preprocessor is enabled by calling
|
||||
`RC.nrmac[module_id]->pre_processor_dl.dl_algo.run()` in `nr_fr1_dlsch_preprocessor()` by default.
|
||||
> Once the NVS algorithm is applied to the slice-level scheduler, the user-level scheduler is enabled by calling
|
||||
> `si->s[maxidx]->dl_algo.run()` in `nvs_nr_dl()`.
|
||||
|
||||
Note that the algorithm of user-level scheduler also can be customized for each slice, for an example,
|
||||
the user-level scheduling algorithm `nr_proportional_fair_wbcqi_dl` is defined in `gNB_scheduler_dlsch.c`:
|
||||
```c
|
||||
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
|
||||
};
|
||||
```
|
||||
By following above structure `nr_dl_sched_algo_t`,
|
||||
the other user-level scheduling algorithm can be implemented and be assigned to different slices,
|
||||
> for an example, in `addmod_nvs_nr_slice_dl()`:
|
||||
> ```c
|
||||
> s->dl_algo = *(nr_dl_sched_algo_t*) algo;
|
||||
> ```
|
||||
|
||||
## Examples
|
||||
### Enable 3GPP slices (NSSAI-based) by using NVS algorithm to achieve minimum PRB Ratio
|
||||
The NVS scheduling algorithm, as detailed in the referenced paper [3],
|
||||
operates by determining the maximum weight for slices in each time slot.
|
||||
The weight represents the marginal utility of each slice with respect to the achieved cumulative fraction of resources.
|
||||
At each time slot,
|
||||
the algorithm selects the slice with the highest weight,
|
||||
and allocate the resource to the UEs associated to the selected slice.
|
||||
> For instance, if there are two slices
|
||||
and both are set to use 50% of the resources from system (assuming there are 8 downlink slots in 5 sub-frames),
|
||||
every time slot will utilize 100% of Resource Blocks (RBs) for the chosen slice.
|
||||
To be more concrete, the selected slots for two slices could be as follows:
|
||||
> - slice 1 occupies 0, 2, 4, 6th slot
|
||||
> - slice 2 occupies 1, 3, 5, 7th slot
|
||||
|
||||
Based on the _RRMPolicyRatio_ defined by 3GPP TS 28.541 v16.6, as shown in below figure,
|
||||
the prioritized resource can be achieved by using type `NVS_RES` and parameter `pct_reserved` from NVS algorithm.
|
||||
These resources are preferentially used by the associated slice, and
|
||||
are guaranteed for use by the associated slice when it needs to use them.
|
||||
When not used, these resources may be used by other slices.
|
||||
Therefore, in the RC RAN function, `pct_reserved` is assigned by `Min_PRB_Policy_Ratio` which is given by xApp via Near-Real-Time RIC,
|
||||
to configure the slices.
|
||||
|
||||

|
||||
### References
|
||||
- [1] [SLICING IN HETEROGENEOUS SOFTWARE-DEFINED RADIO ACCESS NETWORKS](https://www.eurecom.fr/en/publication/6635)
|
||||
- [2] [FLEXSLICE: FLEXIBLE AND REAL-TIME PROGRAMMABLE RAN SLICING FRAMEWORK](https://www.eurecom.fr/en/publication/7416)
|
||||
- [3] [NVS: A Substrate for Virtualizing Wireless Resources in Cellular Networks](https://ieeexplore.ieee.org/document/6117098)
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
602
openair2/LAYER2/NR_MAC_gNB/slicing/nr_slicing.c
Normal file
602
openair2/LAYER2/NR_MAC_gNB/slicing/nr_slicing.c
Normal file
@@ -0,0 +1,602 @@
|
||||
/*
|
||||
* 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 "NR_MAC_COMMON/nr_mac_extern.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 "openair2/LAYER2/RLC/rlc.h"
|
||||
|
||||
#include "nr_slicing.h"
|
||||
#include "nr_slicing_internal.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)
|
||||
|
||||
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);
|
||||
for (int l = 0; l < sched_ctrl->dl_lc_num; ++l) {
|
||||
lcid = sched_ctrl->dl_lc_ids[l];
|
||||
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);
|
||||
LOG_D(NR_MAC, "add lcid %ld to slice idx %d\n", lcid, i);
|
||||
|
||||
if (!check_nr_list(&new_ue->dl_id, si->s[i]->id)) {
|
||||
add_nr_list(&new_ue->dl_id, si->s[i]->id);
|
||||
LOG_D(NR_MAC, "add dl id %d to new UE rnti %x\n", si->s[i]->id, new_ue->rnti);
|
||||
}
|
||||
|
||||
UE_iterator(si->s[i]->UE_list, UE) {
|
||||
if (UE->rnti == new_ue->rnti)
|
||||
break;
|
||||
}
|
||||
if (UE == NULL) {
|
||||
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;
|
||||
LOG_W(NR_MAC, "Matched slice, 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);
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG_D(NR_MAC, "cannot find matched slice (lcid %ld <sst %d sd %d>, slice idx %d <sst %d sd %d>), do nothing for UE rnti 0x%04x\n",
|
||||
lcid, sched_ctrl->dl_lc_nssai[lcid].sst, sched_ctrl->dl_lc_nssai[lcid].sd, i, si->s[i]->nssai.sst, si->s[i]->nssai.sd, new_ue->rnti);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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, TYPE_C_RNTI_);
|
||||
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;
|
||||
// we reserved 5% resource for RRC connection while UE is connecting before created slice or
|
||||
// PDU setup while UE is trying to connect after created slice
|
||||
dlp->pct_reserved = 0.05f;
|
||||
nr_dl_sched_algo_t *algo = &RC.nrmac[mod_id]->pre_processor_dl.dl_algo;
|
||||
algo->data = NULL;
|
||||
// default slice: sst = 1, sd = 0x000000, id = 999, label = default
|
||||
nssai_t nssai = {.sst = 0, .sd = 0};
|
||||
const int rc = addmod_nvs_nr_slice_dl(si, 99, nssai, strdup("default"), algo, dlp);
|
||||
LOG_W(NR_MAC, "Add default DL slice id 99, label default, sst %d, sd %d, slice sched algo NVS_CAPACITY, pct_reserved %.2f, ue sched algo %s\n", nssai.sst, nssai.sd, dlp->pct_reserved, algo->name);
|
||||
DevAssert(0 == rc);
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
75
openair2/LAYER2/NR_MAC_gNB/slicing/nr_slicing.h
Normal file
75
openair2/LAYER2/NR_MAC_gNB/slicing/nr_slicing.h
Normal 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__ */
|
||||
48
openair2/LAYER2/NR_MAC_gNB/slicing/nr_slicing_internal.h
Normal file
48
openair2/LAYER2/NR_MAC_gNB/slicing/nr_slicing_internal.h
Normal 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__ */
|
||||
@@ -478,6 +478,14 @@ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t
|
||||
PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, GNB_FLAG_YES, UE->rrc_ue_id, 0, 0);
|
||||
UE->amf_ue_ngap_id = req->amf_ue_ngap_id;
|
||||
|
||||
/* GUAMI */
|
||||
UE->ue_guami.mcc = req->guami.mcc;
|
||||
UE->ue_guami.mnc = req->guami.mnc;
|
||||
UE->ue_guami.mnc_len = req->guami.mnc_len;
|
||||
UE->ue_guami.amf_region_id = req->guami.amf_region_id;
|
||||
UE->ue_guami.amf_set_id = req->guami.amf_set_id;
|
||||
UE->ue_guami.amf_pointer = req->guami.amf_pointer;
|
||||
|
||||
/* NAS PDU */
|
||||
// this is malloced pointers, we pass it for later free()
|
||||
UE->nas_pdu = req->nas_pdu;
|
||||
|
||||
@@ -746,7 +746,7 @@ static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32
|
||||
OCTET_STRING_TO_INT8(&ie->value.choice.GUAMI.aMFRegionID, msg->guami.amf_region_id);
|
||||
OCTET_STRING_TO_INT16(&ie->value.choice.GUAMI.aMFSetID, msg->guami.amf_set_id);
|
||||
OCTET_STRING_TO_INT8(&ie->value.choice.GUAMI.aMFPointer, msg->guami.amf_pointer);
|
||||
|
||||
NGAP_INFO("Initial Context Request, GUAMI mcc %d mnc %d mnc_len %d\n", msg->guami.mcc, msg->guami.mnc, msg->guami.mnc_len);
|
||||
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_PDUSessionResourceSetupListCxtReq, false);
|
||||
if (ie != NULL) {
|
||||
msg->nb_of_pdusessions = ie->value.choice.PDUSessionResourceSetupListCxtReq.list.count;
|
||||
@@ -799,6 +799,7 @@ static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32
|
||||
} 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 */
|
||||
@@ -979,6 +980,7 @@ static int ngap_gNB_handle_pdusession_setup_request(sctp_assoc_t assoc_id, uint3
|
||||
} 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);
|
||||
|
||||
Reference in New Issue
Block a user