Commit 5aba7ac9 authored by Guido Casati's avatar Guido Casati Committed by Guido Casati

Handling setup of multiple DRBs with different QoS flows in GTP-U

* current assumption: multiple DRBs, 1 QoS flow per DRB

Set QFI in GTP-U data request in a multi-DRB with multi-QoS scenario:

* each GTP-U packet processed within the GTP-U tunnel
  and which belongs to a QoS Flow mapped to a DRB
  has to be marked with the corresponding QFI
* Set QFI in GTP-U data request
* hardcoded to -1 in F1 interface, since it is not relevant
parent 84f6c0a5
...@@ -118,6 +118,7 @@ typedef struct gtpv1u_tunnel_data_req_s { ...@@ -118,6 +118,7 @@ typedef struct gtpv1u_tunnel_data_req_s {
uint32_t offset; ///< start of message offset in buffer uint32_t offset; ///< start of message offset in buffer
ue_id_t ue_id; ue_id_t ue_id;
rb_id_t bearer_id; rb_id_t bearer_id;
int qfi;
} gtpv1u_tunnel_data_req_t; } gtpv1u_tunnel_data_req_t;
typedef struct gtpv1u_enb_data_forwarding_req_s { typedef struct gtpv1u_enb_data_forwarding_req_s {
...@@ -171,6 +172,16 @@ typedef struct { ...@@ -171,6 +172,16 @@ typedef struct {
char localPortStr[256]; char localPortStr[256];
} Gtpv1uReq; } Gtpv1uReq;
/**
* @brief QoS Flow information for a given bearer
*/
typedef struct gtpv1u_qos_s {
/* QFIs list for each Bearer (0 ... Max Number of QFIs per Bearer) */
int qfi[NR_GTPV1U_MAX_QFI_PER_BEARER];
/* Bearer ID */
int rb_id;
} gtpv1u_qos_t;
/** /**
* @brief GTP-U Create Tunnel Request * @brief GTP-U Create Tunnel Request
*/ */
...@@ -178,8 +189,8 @@ typedef struct gtpv1u_gnb_create_tunnel_req_s { ...@@ -178,8 +189,8 @@ typedef struct gtpv1u_gnb_create_tunnel_req_s {
ue_id_t ue_id; ue_id_t ue_id;
/* Outgoing TEID for the GTP tunnel request */ /* Outgoing TEID for the GTP tunnel request */
teid_t outgoing_teid; teid_t outgoing_teid;
/* Outgoing QFIs for each Bearer within the tunnel (assuming 1 QoS Flow only) */ /* Outgoing QFIs for each Bearer within the tunnel (0 ... Max Number of Bearers per PDU Session) */
int outgoing_qfi; gtpv1u_qos_t outgoing_qfi[NR_GTPV1U_MAX_BEARERS_PER_UE];
/* PDU Session ID for the GTP tunnel request */ /* PDU Session ID for the GTP tunnel request */
pdusessionid_t pdusession_id; pdusessionid_t pdusession_id;
/* Incoming RB for the GTP tunnel request */ /* Incoming RB for the GTP tunnel request */
......
...@@ -54,15 +54,14 @@ static int drb_gtpu_create(instance_t instance, ...@@ -54,15 +54,14 @@ static int drb_gtpu_create(instance_t instance,
gtpCallback callBack, gtpCallback callBack,
gtpv1u_gnb_create_tunnel_resp_t *resp_f1) gtpv1u_gnb_create_tunnel_resp_t *resp_f1)
{ {
const int bearer_id = 0;
int qfi = -1; // don't put PDU session marker in GTP for F1-U int qfi = -1; // don't put PDU session marker in GTP for F1-U
gtpv1u_gnb_create_tunnel_req_t create_tunnel_req = { gtpv1u_gnb_create_tunnel_req_t create_tunnel_req = {.ue_id = ue_id,
.ue_id = ue_id, .outgoing_teid = drb->up_ul_tnl[0].teid,
.outgoing_teid = drb->up_ul_tnl[0].teid, .outgoing_qfi[bearer_id].qfi[0] = qfi,
.outgoing_qfi = qfi, .pdusession_id = drb->drb_id,
.pdusession_id = drb->drb_id, .incoming_rb_id = drb->drb_id,
.incoming_rb_id = drb->drb_id, .dst_addr.length = 32};
.dst_addr.length = 32
};
memcpy(&create_tunnel_req.dst_addr.buffer, &drb->up_ul_tnl[0].tl_address, sizeof(uint8_t) * 4); // only IPv4 now memcpy(&create_tunnel_req.dst_addr.buffer, &drb->up_ul_tnl[0].tl_address, sizeof(uint8_t) * 4); // only IPv4 now
LOG_D(E1AP, "Incoming RB %ld / Outgoing RB %ld - UL TEID %d QFI %d\n", drb->drb_id, drb->drb_id, drb->up_ul_tnl[0].teid, qfi); LOG_D(E1AP, "Incoming RB %ld / Outgoing RB %ld - UL TEID %d QFI %d\n", drb->drb_id, drb->drb_id, drb->up_ul_tnl[0].teid, qfi);
// we use gtpv1u_create_ngu_tunnel because it returns the interface // we use gtpv1u_create_ngu_tunnel because it returns the interface
......
...@@ -98,14 +98,15 @@ static int drb_gtpu_create(instance_t instance, ...@@ -98,14 +98,15 @@ static int drb_gtpu_create(instance_t instance,
teid_t dummy_teid = 0xffff; // we will update later with answer from DU teid_t dummy_teid = 0xffff; // we will update later with answer from DU
in_addr_t dummy_address = {0}; // IPv4, updated later with answer from DU in_addr_t dummy_address = {0}; // IPv4, updated later with answer from DU
gtpCallback callBack = cu_f1u_data_req; gtpCallback callBack = cu_f1u_data_req;
const int bearer_id = 0; // 1 DRB
int qfi = -1; // don't put PDU session marker in GTP for F1-U int qfi = -1; // don't put PDU session marker in GTP for F1-U
gtpv1u_gnb_create_tunnel_req_t create_tunnel_req = { gtpv1u_gnb_create_tunnel_req_t create_tunnel_req = {
.ue_id = ue_id, .ue_id = ue_id,
.outgoing_teid = dummy_teid, .outgoing_teid = dummy_teid,
.outgoing_qfi = qfi, .outgoing_qfi[bearer_id].qfi[0] = qfi,
.pdusession_id = drb->id, .pdusession_id = drb->id,
.incoming_rb_id = drb->id, .incoming_rb_id = drb->id,
.dst_addr.length = 32, .dst_addr.length = 32,
}; };
memcpy(&create_tunnel_req.dst_addr.buffer, &dummy_address, sizeof(uint8_t) * 4); memcpy(&create_tunnel_req.dst_addr.buffer, &dummy_address, sizeof(uint8_t) * 4);
LOG_D(E1AP, "In %s: Incoming RB ID %ld Outgoing RB ID %ld - UL TEID (dummy) %d QFI %d\n", __func__, drb->id, drb->id, dummy_teid, qfi); LOG_D(E1AP, "In %s: Incoming RB ID %ld Outgoing RB ID %ld - UL TEID (dummy) %d QFI %d\n", __func__, drb->id, drb->id, dummy_teid, qfi);
...@@ -131,20 +132,25 @@ static void fill_gtpu_n3_req(gtpv1u_gnb_create_tunnel_req_t *req_n3, const pdu_s ...@@ -131,20 +132,25 @@ static void fill_gtpu_n3_req(gtpv1u_gnb_create_tunnel_req_t *req_n3, const pdu_s
} }
/** /**
* @brief Loop though the number of QoS Flows to setup per DRB * @brief Loop though the number of QoS Flows to setup per DRB and return DRB-to-QoS mapping
*/ */
static int process_qosflowSetup(DRB_nGRAN_setup_t *resp_drb, const DRB_nGRAN_to_setup_t *req_drb) static gtpv1u_qos_t process_qosflowSetup(DRB_nGRAN_setup_t *resp_drb, const DRB_nGRAN_to_setup_t *req_drb)
{ {
int outgoing_qfi; gtpv1u_qos_t outgoing_qfi;
resp_drb->numQosFlowSetup = 1; int k;
/* Loop though the number of QoS Flows to setup resp_drb->numQosFlowSetup = req_drb->numQosFlow2Setup;
* NOTE (A) only 1 QFI per DRB */ /* Loop though the number of QoS Flows to setup for current DRB */
for (int k = 0; k < resp_drb->numQosFlowSetup; k++) { outgoing_qfi.rb_id = resp_drb->id;
for (k = 0; k < resp_drb->numQosFlowSetup; k++) {
const qos_flow_to_setup_t *qosflow2Setup = &req_drb->qosFlows[k]; const qos_flow_to_setup_t *qosflow2Setup = &req_drb->qosFlows[k];
qos_flow_setup_t *qosflowSetup = &resp_drb->qosFlows[k]; qos_flow_setup_t *qosflowSetup = &resp_drb->qosFlows[k];
qosflowSetup->qfi = qosflow2Setup->qfi; qosflowSetup->qfi = qosflow2Setup->qfi;
outgoing_qfi = qosflowSetup->qfi; outgoing_qfi.qfi[k] = qosflowSetup->qfi;
LOG_D(E1AP, "DRB %ld with QFI %ld to setup\n", resp_drb->id, qosflow2Setup->qfi); LOG_D(E1AP, "DRB %d with QFI %ld to setup\n", outgoing_qfi.rb_id, qosflow2Setup->qfi);
}
/* Set remaining QFIs to -1 */
for (int r = k + 1; r < SDAP_MAX_QFI; r++) {
outgoing_qfi.qfi[r] = -1;
} }
return outgoing_qfi; return outgoing_qfi;
} }
...@@ -209,7 +215,7 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) ...@@ -209,7 +215,7 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req)
DRB_nGRAN_setup_t *resp_drb = &resp_pdu->DRBnGRanList[d]; DRB_nGRAN_setup_t *resp_drb = &resp_pdu->DRBnGRanList[d];
resp_drb->id = req_drb->id; resp_drb->id = req_drb->id;
/* Fill PDU session markers */ /* Fill PDU session markers */
req_n3.outgoing_qfi = process_qosflowSetup(resp_drb, req_drb); req_n3.outgoing_qfi[d] = process_qosflowSetup(resp_drb, req_drb);
// create PDCP bearers. This will also create SDAP bearers // create PDCP bearers. This will also create SDAP bearers
NR_DRB_ToAddModList_t DRB_configList = {0}; NR_DRB_ToAddModList_t DRB_configList = {0};
fill_DRB_configList_e1(&DRB_configList, req_pdu); fill_DRB_configList_e1(&DRB_configList, req_pdu);
......
...@@ -730,6 +730,7 @@ static void deliver_pdu_drb_gnb(void *deliver_pdu_data, ue_id_t ue_id, int rb_id ...@@ -730,6 +730,7 @@ static void deliver_pdu_drb_gnb(void *deliver_pdu_data, ue_id_t ue_id, int rb_id
req->offset = GTPU_HEADER_OVERHEAD_MAX; req->offset = GTPU_HEADER_OVERHEAD_MAX;
req->ue_id = ue_id; // use CU UE ID as GTP will use that to look up TEID req->ue_id = ue_id; // use CU UE ID as GTP will use that to look up TEID
req->bearer_id = rb_id; req->bearer_id = rb_id;
req->qfi = -1;
LOG_D(PDCP, "%s() (drb %d) sending message to gtp size %d\n", __func__, rb_id, size); LOG_D(PDCP, "%s() (drb %d) sending message to gtp size %d\n", __func__, rb_id, size);
extern instance_t CUuniqInstance; extern instance_t CUuniqInstance;
itti_send_msg_to_task(TASK_GTPV1_U, CUuniqInstance, message_p); itti_send_msg_to_task(TASK_GTPV1_U, CUuniqInstance, message_p);
......
...@@ -503,6 +503,7 @@ rb_found: ...@@ -503,6 +503,7 @@ rb_found:
req->offset = 0; req->offset = 0;
req->ue_id = ue->ue_id; req->ue_id = ue->ue_id;
req->bearer_id=rb_id; req->bearer_id=rb_id;
req->qfi = -1;
LOG_D(RLC, "Received uplink user-plane traffic at RLC-DU to be sent to the CU, size %d \n", size); LOG_D(RLC, "Received uplink user-plane traffic at RLC-DU to be sent to the CU, size %d \n", size);
extern instance_t DUuniqInstance; extern instance_t DUuniqInstance;
itti_send_msg_to_task(TASK_GTPV1_U, DUuniqInstance, msg); itti_send_msg_to_task(TASK_GTPV1_U, DUuniqInstance, msg);
......
...@@ -396,18 +396,31 @@ void trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession ...@@ -396,18 +396,31 @@ void trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession
pdu->teId = session->gtp_teid; pdu->teId = session->gtp_teid;
memcpy(&pdu->tlAddress, session->upf_addr.buffer, 4); // Fixme: dirty IPv4 target memcpy(&pdu->tlAddress, session->upf_addr.buffer, 4); // Fixme: dirty IPv4 target
/* we assume for the moment one DRB per PDU session. Activate the bearer, /* we currently assume 1 QoS Flow per DRB, therefore we setup
* and configure in RRC. */ * as many DRBs as the number of QoS Flows decoded from the
int drb_id = get_next_available_drb_id(UE); * PDU Session Resource Setup */
drb_t *rrc_drb = generateDRB(UE, pdu->numDRB2Setup = session->nb_qos; // TODO: update when iplementing multiple QoS per DRB
drb_id, /* Loop through the DRBs to setup */
pduSession, for (int j = 0; j < pdu->numDRB2Setup; j++) {
rrc->configuration.enable_sdap, int drb_id = get_next_available_drb_id(UE);
rrc->security.do_drb_integrity, /* Fetch QoS Flow from the PDU Session QoS Flows list
rrc->security.do_drb_ciphering); * NOTE: the assumption is that each DRB is mapped to 1 QoS Flow only
* therefore the QoS flow list item pointer is shifted by j, which is
pdu->numDRB2Setup = 1; // One DRB per PDU Session. TODO: Remove hardcoding * the current DRB to setup */
for (int j=0; j < pdu->numDRB2Setup; j++) { pdusession_level_qos_parameter_t *qos_session = session->qos + j;
int qfi = qos_session->qfi;
int fiveQI = qos_session->fiveQI;
/* generate DRB */
LOG_I(NR_RRC, "Generating DRB %d for QFI %d 5QI %d\n", drb_id, qfi, fiveQI);
drb_t *rrc_drb = generateDRB(UE,
drb_id,
pduSession->param.pdusession_id,
rrc->configuration.enable_sdap,
rrc->security.do_drb_integrity,
rrc->security.do_drb_ciphering,
qfi,
fiveQI);
/* DRB to be setup */
DRB_nGRAN_to_setup_t *drb = pdu->DRBnGRanList + j; DRB_nGRAN_to_setup_t *drb = pdu->DRBnGRanList + j;
drb->id = rrc_drb->drb_id; drb->id = rrc_drb->drb_id;
...@@ -426,11 +439,10 @@ void trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession ...@@ -426,11 +439,10 @@ void trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession
cellGroup->id = 0; // MCG cellGroup->id = 0; // MCG
} }
/* Loop throught the number of QoS flows mapped to this DRB */ /* Loop throught the number of QoS flows mapped to this DRB */
drb->numQosFlow2Setup = 1; // TODO: update when iplementing multiple QoS per DRB: the mapping should come from SDAP drb->numQosFlow2Setup = 1; // NOTE: implementation assumption is 1 QoS Flow per 1 DRB
for (int k = 0; k < drb->numQosFlow2Setup; k++) { for (int k = 0; k < drb->numQosFlow2Setup; k++) {
qos_flow_to_setup_t *qos_flow = drb->qosFlows + k; qos_flow_to_setup_t *qos_flow = drb->qosFlows + k;
pdusession_level_qos_parameter_t *qos_session = session->qos + k; /* QoS Characteristics */
qos_characteristics_t *qos_char = &qos_flow->qos_params.qos_characteristics; qos_characteristics_t *qos_char = &qos_flow->qos_params.qos_characteristics;
qos_flow->qfi = qos_session->qfi; qos_flow->qfi = qos_session->qfi;
qos_char->qos_type = qos_session->fiveQI_type; qos_char->qos_type = qos_session->fiveQI_type;
......
...@@ -85,11 +85,13 @@ drb_t *generateDRB(gNB_RRC_UE_t *ue, ...@@ -85,11 +85,13 @@ drb_t *generateDRB(gNB_RRC_UE_t *ue,
const rrc_pdu_session_param_t *pduSession, const rrc_pdu_session_param_t *pduSession,
bool enable_sdap, bool enable_sdap,
int do_drb_integrity, int do_drb_integrity,
int do_drb_ciphering) int do_drb_ciphering,
int qfi,
int fiveQI)
{ {
DevAssert(ue != NULL); DevAssert(ue != NULL);
LOG_I(NR_RRC, "UE %d: configure DRB ID %d for PDU session ID %d\n", ue->rrc_ue_id, drb_id, pduSession->param.pdusession_id); LOG_I(NR_RRC, "UE %d: configure DRB ID %d for PDU session ID %d\n", ue->rrc_ue_id, drb_id, pdusession_id);
drb_t *est_drb = &ue->established_drbs[drb_id - 1]; drb_t *est_drb = &ue->established_drbs[drb_id - 1];
DevAssert(est_drb->status == DRB_INACTIVE); DevAssert(est_drb->status == DRB_INACTIVE);
...@@ -110,9 +112,9 @@ drb_t *generateDRB(gNB_RRC_UE_t *ue, ...@@ -110,9 +112,9 @@ drb_t *generateDRB(gNB_RRC_UE_t *ue,
est_drb->cnAssociation.sdap_config.sdap_HeaderDL = NR_SDAP_Config__sdap_HeaderDL_absent; est_drb->cnAssociation.sdap_config.sdap_HeaderDL = NR_SDAP_Config__sdap_HeaderDL_absent;
est_drb->cnAssociation.sdap_config.sdap_HeaderUL = NR_SDAP_Config__sdap_HeaderUL_absent; est_drb->cnAssociation.sdap_config.sdap_HeaderUL = NR_SDAP_Config__sdap_HeaderUL_absent;
} }
for (int qos_flow_index = 0; qos_flow_index < pduSession->param.nb_qos; qos_flow_index++) { for (int qos_flow_index = 0; qos_flow_index < 1; qos_flow_index++) { // NOTE: implementation assumption is 1 QoS Flow per 1 DRB
est_drb->cnAssociation.sdap_config.mappedQoS_FlowsToAdd[qos_flow_index] = pduSession->param.qos[qos_flow_index].qfi; est_drb->cnAssociation.sdap_config.mappedQoS_FlowsToAdd[qos_flow_index] = qfi;
if (pduSession->param.qos[qos_flow_index].fiveQI > 5) if (fiveQI > 5)
est_drb->status = DRB_ACTIVE_NONGBR; est_drb->status = DRB_ACTIVE_NONGBR;
else else
est_drb->status = DRB_ACTIVE; est_drb->status = DRB_ACTIVE;
......
...@@ -56,7 +56,9 @@ drb_t *generateDRB(gNB_RRC_UE_t *ue, ...@@ -56,7 +56,9 @@ drb_t *generateDRB(gNB_RRC_UE_t *ue,
const rrc_pdu_session_param_t *pduSession, const rrc_pdu_session_param_t *pduSession,
bool enable_sdap, bool enable_sdap,
int do_drb_integrity, int do_drb_integrity,
int do_drb_ciphering); int do_drb_ciphering,
int qfi,
int fiveQI);
/// @brief return the next available (inactive) DRB ID of UE ue /// @brief return the next available (inactive) DRB ID of UE ue
uint8_t get_next_available_drb_id(gNB_RRC_UE_t *ue); uint8_t get_next_available_drb_id(gNB_RRC_UE_t *ue);
......
...@@ -77,14 +77,8 @@ void sdap_data_ind(rb_id_t pdcp_entity, ...@@ -77,14 +77,8 @@ void sdap_data_ind(rb_id_t pdcp_entity,
return; return;
} }
sdap_entity->rx_entity(sdap_entity, int qfi = sdap_entity->drb2qfi_map(sdap_entity, pdcp_entity);
pdcp_entity, sdap_entity->rx_entity(sdap_entity, pdcp_entity, qfi, is_gnb, has_sdap_rx, pdusession_id, ue_id, buf, size);
is_gnb,
has_sdap_rx,
pdusession_id,
ue_id,
buf,
size);
} }
void set_qfi_pduid(uint8_t qfi, uint8_t pduid){ void set_qfi_pduid(uint8_t qfi, uint8_t pduid){
......
...@@ -232,6 +232,7 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity, ...@@ -232,6 +232,7 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity,
static void nr_sdap_rx_entity(nr_sdap_entity_t *entity, static void nr_sdap_rx_entity(nr_sdap_entity_t *entity,
rb_id_t pdcp_entity, rb_id_t pdcp_entity,
int qfi,
int is_gnb, int is_gnb,
bool has_sdap_rx, bool has_sdap_rx,
int pdusession_id, int pdusession_id,
...@@ -271,12 +272,13 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity, ...@@ -271,12 +272,13 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity,
gtpv1u_tunnel_data_req_t *req = &GTPV1U_TUNNEL_DATA_REQ(message_p); gtpv1u_tunnel_data_req_t *req = &GTPV1U_TUNNEL_DATA_REQ(message_p);
uint8_t *gtpu_buffer_p = (uint8_t *) (req + 1); uint8_t *gtpu_buffer_p = (uint8_t *) (req + 1);
memcpy(gtpu_buffer_p + GTPU_HEADER_OVERHEAD_MAX, buf + offset, size - offset); memcpy(gtpu_buffer_p + GTPU_HEADER_OVERHEAD_MAX, buf + offset, size - offset);
req->buffer = gtpu_buffer_p; req->buffer = gtpu_buffer_p;
req->length = size - offset; req->length = size - offset;
req->offset = GTPU_HEADER_OVERHEAD_MAX; req->offset = GTPU_HEADER_OVERHEAD_MAX;
req->ue_id = ue_id; req->ue_id = ue_id;
req->bearer_id = pdusession_id; req->bearer_id = pdusession_id;
LOG_D(SDAP, "%s() sending message to gtp size %d\n", __func__, size-offset); req->qfi = qfi;
LOG_D(SDAP, "%s(): sending message to gtp size %d for QFI %d PDU SESSION %d \n", __func__, size - offset, qfi, pdusession_id);
// very very dirty hack gloabl var N3GTPUInst // very very dirty hack gloabl var N3GTPUInst
itti_send_msg_to_task(TASK_GTPV1_U, *N3GTPUInst, message_p); itti_send_msg_to_task(TASK_GTPV1_U, *N3GTPUInst, message_p);
} else { //nrUE } else { //nrUE
...@@ -538,6 +540,7 @@ nr_sdap_entity_t *new_nr_sdap_entity(int is_gnb, ...@@ -538,6 +540,7 @@ nr_sdap_entity_t *new_nr_sdap_entity(int is_gnb,
sdap_entity->qfi2drb_map_update = nr_sdap_qfi2drb_map_update; sdap_entity->qfi2drb_map_update = nr_sdap_qfi2drb_map_update;
sdap_entity->qfi2drb_map_delete = nr_sdap_qfi2drb_map_del; sdap_entity->qfi2drb_map_delete = nr_sdap_qfi2drb_map_del;
sdap_entity->qfi2drb_map = nr_sdap_qfi2drb; sdap_entity->qfi2drb_map = nr_sdap_qfi2drb;
sdap_entity->drb2qfi_map = nr_sdap_drb2qfi;
/* update SDAP entity list pointers */ /* update SDAP entity list pointers */
sdap_entity->next_entity = sdap_info.sdap_entity_llist; sdap_entity->next_entity = sdap_info.sdap_entity_llist;
sdap_info.sdap_entity_llist = sdap_entity; sdap_info.sdap_entity_llist = sdap_entity;
......
...@@ -94,7 +94,7 @@ typedef struct nr_sdap_entity_s { ...@@ -94,7 +94,7 @@ typedef struct nr_sdap_entity_s {
void (*qfi2drb_map_update)(struct nr_sdap_entity_s *entity, uint8_t qfi, rb_id_t drb, bool has_sdap_rx, bool has_sdap_tx); void (*qfi2drb_map_update)(struct nr_sdap_entity_s *entity, uint8_t qfi, rb_id_t drb, bool has_sdap_rx, bool has_sdap_tx);
void (*qfi2drb_map_delete)(struct nr_sdap_entity_s *entity, uint8_t qfi); void (*qfi2drb_map_delete)(struct nr_sdap_entity_s *entity, uint8_t qfi);
rb_id_t (*qfi2drb_map)(struct nr_sdap_entity_s *entity, uint8_t qfi); rb_id_t (*qfi2drb_map)(struct nr_sdap_entity_s *entity, uint8_t qfi);
int (*drb2qfi_map)(struct nr_sdap_entity_s *entity, rb_id_t drb_id);
nr_sdap_ul_hdr_t (*sdap_construct_ctrl_pdu)(uint8_t qfi); nr_sdap_ul_hdr_t (*sdap_construct_ctrl_pdu)(uint8_t qfi);
rb_id_t (*sdap_map_ctrl_pdu)(struct nr_sdap_entity_s *entity, rb_id_t pdcp_entity, int map_type, uint8_t dl_qfi); rb_id_t (*sdap_map_ctrl_pdu)(struct nr_sdap_entity_s *entity, rb_id_t pdcp_entity, int map_type, uint8_t dl_qfi);
void (*sdap_submit_ctrl_pdu)(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu); void (*sdap_submit_ctrl_pdu)(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu);
...@@ -115,6 +115,7 @@ typedef struct nr_sdap_entity_s { ...@@ -115,6 +115,7 @@ typedef struct nr_sdap_entity_s {
void (*rx_entity)(struct nr_sdap_entity_s *entity, void (*rx_entity)(struct nr_sdap_entity_s *entity,
rb_id_t pdcp_entity, rb_id_t pdcp_entity,
int qfi,
int is_gnb, int is_gnb,
bool has_sdap_rx, bool has_sdap_rx,
int pdusession_id, int pdusession_id,
......
...@@ -104,7 +104,7 @@ typedef struct gtpv1u_bearer_s { ...@@ -104,7 +104,7 @@ typedef struct gtpv1u_bearer_s {
tcp_udp_port_t outgoing_port; tcp_udp_port_t outgoing_port;
uint16_t seqNum; uint16_t seqNum;
uint8_t npduNum; uint8_t npduNum;
int outgoing_qfi; gtpv1u_qos_t outgoing_qfi[NR_GTPV1U_MAX_BEARERS_PER_UE];
} gtpv1u_bearer_t; } gtpv1u_bearer_t;
typedef struct { typedef struct {
...@@ -291,6 +291,7 @@ static void gtpv1uSend(instance_t instance, gtpv1u_tunnel_data_req_t *req, bool ...@@ -291,6 +291,7 @@ static void gtpv1uSend(instance_t instance, gtpv1u_tunnel_data_req_t *req, bool
size_t length=req->length; size_t length=req->length;
ue_id_t ue_id=req->ue_id; ue_id_t ue_id=req->ue_id;
int bearer_id=req->bearer_id; int bearer_id=req->bearer_id;
int qfi = req->qfi;
pthread_mutex_lock(&globGtp.gtp_lock); pthread_mutex_lock(&globGtp.gtp_lock);
getInstRetVoid(compatInst(instance)); getInstRetVoid(compatInst(instance));
getUeRetVoid(inst, ue_id); getUeRetVoid(inst, ue_id);
...@@ -316,12 +317,27 @@ static void gtpv1uSend(instance_t instance, gtpv1u_tunnel_data_req_t *req, bool ...@@ -316,12 +317,27 @@ static void gtpv1uSend(instance_t instance, gtpv1u_tunnel_data_req_t *req, bool
gtpv1u_bearer_t tmp=ptr2->second; gtpv1u_bearer_t tmp=ptr2->second;
pthread_mutex_unlock(&globGtp.gtp_lock); pthread_mutex_unlock(&globGtp.gtp_lock);
if (tmp.outgoing_qfi != -1) { int j;
rb_id_t rb_id;
/* Check whether the QFI in the data request
for this GTP-U packet is mapped to a bearer */
bool addExtHeader = false;
for (j = 0; j < NR_GTPV1U_MAX_BEARERS_PER_UE; j++) {
for (int i = 0; i < NR_GTPV1U_MAX_QFI_PER_BEARER; i++) {
if (tmp.outgoing_qfi[j].qfi[i] == qfi && tmp.outgoing_qfi[j].qfi[i] != -1) {
rb_id = tmp.outgoing_qfi[j].rb_id;
addExtHeader = true;
LOG_D(GTPU, "QoS Flow %d mapped to DRB %ld\n", qfi, rb_id);
}
}
}
if (addExtHeader) {
/* we add GTP-U extension header */
Gtpv1uExtHeaderT ext = { 0 }; Gtpv1uExtHeaderT ext = { 0 };
ext.ExtHeaderLen = 1; // in quad bytes EXT_HDR_LNTH_OCTET_UNITS ext.ExtHeaderLen = 1; // in quad bytes EXT_HDR_LNTH_OCTET_UNITS
ext.pdusession_cntr.spare = 0; ext.pdusession_cntr.spare = 0;
ext.pdusession_cntr.PDU_type = UL_PDU_SESSION_INFORMATION; ext.pdusession_cntr.PDU_type = UL_PDU_SESSION_INFORMATION;
ext.pdusession_cntr.QFI = tmp.outgoing_qfi; ext.pdusession_cntr.QFI = qfi;
ext.pdusession_cntr.Reflective_QoS_activation = false; ext.pdusession_cntr.Reflective_QoS_activation = false;
ext.pdusession_cntr.Paging_Policy_Indicator = false; ext.pdusession_cntr.Paging_Policy_Indicator = false;
ext.NextExtHeaderType = NO_MORE_EXT_HDRS; ext.NextExtHeaderType = NO_MORE_EXT_HDRS;
...@@ -555,11 +571,12 @@ teid_t newGtpuCreateTunnel(instance_t instance, ...@@ -555,11 +571,12 @@ teid_t newGtpuCreateTunnel(instance_t instance,
int incoming_bearer_id, int incoming_bearer_id,
int outgoing_bearer_id, int outgoing_bearer_id,
teid_t outgoing_teid, teid_t outgoing_teid,
int outgoing_qfi, const gtpv1u_qos_t outgoing_qfi[NR_GTPV1U_MAX_BEARERS_PER_UE],
transport_layer_addr_t remoteAddr, transport_layer_addr_t remoteAddr,
int port, int port,
gtpCallback callBack, gtpCallback callBack,
gtpCallbackSDAP callBackSDAP) { gtpCallbackSDAP callBackSDAP)
{
pthread_mutex_lock(&globGtp.gtp_lock); pthread_mutex_lock(&globGtp.gtp_lock);
getInstRetInt(compatInst(instance)); getInstRetInt(compatInst(instance));
auto it=inst->ue2te_mapping.find(ue_id); auto it=inst->ue2te_mapping.find(ue_id);
...@@ -610,7 +627,7 @@ teid_t newGtpuCreateTunnel(instance_t instance, ...@@ -610,7 +627,7 @@ teid_t newGtpuCreateTunnel(instance_t instance,
tmp->teid_incoming = incoming_teid; tmp->teid_incoming = incoming_teid;
tmp->outgoing_port=port; tmp->outgoing_port=port;
tmp->teid_outgoing= outgoing_teid; tmp->teid_outgoing= outgoing_teid;
tmp->outgoing_qfi=outgoing_qfi; memcpy(tmp->outgoing_qfi, outgoing_qfi, sizeof(gtpv1u_qos_t) * NR_GTPV1U_MAX_BEARERS_PER_UE);
pthread_mutex_unlock(&globGtp.gtp_lock); pthread_mutex_unlock(&globGtp.gtp_lock);
char ip4[INET_ADDRSTRLEN]; char ip4[INET_ADDRSTRLEN];
char ip6[INET6_ADDRSTRLEN]; char ip6[INET6_ADDRSTRLEN];
...@@ -648,12 +665,18 @@ int gtpv1u_create_s1u_tunnel(instance_t instance, ...@@ -648,12 +665,18 @@ int gtpv1u_create_s1u_tunnel(instance_t instance,
"From legacy code not clear, seems impossible (bearer=%d)\n", "From legacy code not clear, seems impossible (bearer=%d)\n",
create_tunnel_req->eps_bearer_id[i]); create_tunnel_req->eps_bearer_id[i]);
int incoming_rb_id=create_tunnel_req->eps_bearer_id[i]-4; int incoming_rb_id=create_tunnel_req->eps_bearer_id[i]-4;
gtpv1u_qos_t outgoing_qfi[NR_GTPV1U_MAX_BEARERS_PER_UE];
for (int i = 0; i < NR_GTPV1U_MAX_BEARERS_PER_UE; ++i) {
for (int j = 0; j < NR_GTPV1U_MAX_QFI_PER_BEARER; ++j) {
outgoing_qfi[i].qfi[j] = -1; // no pdu session in 4G
}
}
teid_t teid = newGtpuCreateTunnel(compatInst(instance), teid_t teid = newGtpuCreateTunnel(compatInst(instance),
create_tunnel_req->rnti, create_tunnel_req->rnti,
incoming_rb_id, incoming_rb_id,
create_tunnel_req->eps_bearer_id[i], create_tunnel_req->eps_bearer_id[i],
create_tunnel_req->sgw_S1u_teid[i], create_tunnel_req->sgw_S1u_teid[i],
-1, // no pdu session in 4G outgoing_qfi,
create_tunnel_req->sgw_addr[i], create_tunnel_req->sgw_addr[i],
dstport, dstport,
callBack, callBack,
......
...@@ -88,7 +88,7 @@ extern "C" { ...@@ -88,7 +88,7 @@ extern "C" {
int incoming_bearer_id, int incoming_bearer_id,
int outgoing_rb_id, int outgoing_rb_id,
teid_t teid, teid_t teid,
int outgoing_qfi, const gtpv1u_qos_t outgoing_qfi[NR_GTPV1U_MAX_BEARERS_PER_UE],
transport_layer_addr_t remoteAddr, transport_layer_addr_t remoteAddr,
int port, int port,
gtpCallback callBack, gtpCallback callBack,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment