fix: DRB lost issue when additional TFTs needs to be added to existing bearer with TFTs

This commit address the issue where a bearer with particular
PCC rule name exists with TFTs and addtional TFTs needs to be added
to same bearer and DRB lost is reported by UE.

This is achieved by creating EPS Bearer Level Traffic Flow Template
with TFT operation code as 'OGS_GTP_TFT_CODE_ADD_PACKET_FILTERS_TO_EXISTING_TFT' in
above scenario rather than use 'OGS_GTP_TFT_CODE_CREATE_NEW_TFT' at all times.
And, not remove existing packet filters for the bearer.
This commit is contained in:
herlesupreeth 2021-05-26 21:29:32 +02:00
parent 64508c2e5c
commit 4d6692d8fe
3 changed files with 69 additions and 29 deletions

View File

@ -82,30 +82,39 @@ static void bearer_timeout(ogs_gtp_xact_t *xact, void *data)
* TFT : Local <UE_IP> <UE_PORT> REMOTE <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT>
*/
static void encode_traffic_flow_template(
ogs_gtp_tft_t *tft, smf_bearer_t *bearer)
ogs_gtp_tft_t *tft, ogs_list_t *pf_list, uint8_t tft_operation_code)
{
int i;
smf_pf_t *pf = NULL;
ogs_assert(tft);
ogs_assert(bearer);
ogs_assert(pf_list);
memset(tft, 0, sizeof(*tft));
tft->code = OGS_GTP_TFT_CODE_CREATE_NEW_TFT;
tft->code = tft_operation_code;
i = 0;
pf = smf_pf_first(bearer);
while (pf) {
tft->pf[i].direction = pf->direction;
tft->pf[i].identifier = pf->identifier - 1;
tft->pf[i].precedence = pf->precedence - 1;
if (tft_operation_code != OGS_GTP_TFT_CODE_DELETE_EXISTING_TFT &&
tft_operation_code != OGS_GTP_TFT_CODE_NO_TFT_OPERATION) {
pf = ogs_list_first(pf_list);
while (pf) {
tft->pf[i].identifier = pf->identifier - 1;
ogs_pf_content_from_ipfw_rule(
pf->direction, &tft->pf[i].content, &pf->ipfw_rule);
/* Deletion of packet filters from existing requires only the identifier */
if (tft_operation_code !=
OGS_GTP_TFT_CODE_DELETE_PACKET_FILTERS_FROM_EXISTING) {
i++;
tft->pf[i].direction = pf->direction;
tft->pf[i].precedence = pf->precedence - 1;
pf = smf_pf_next(pf);
ogs_pf_content_from_ipfw_rule(
pf->direction, &tft->pf[i].content, &pf->ipfw_rule);
}
i++;
pf = ogs_list_next(pf);
}
}
tft->num_of_packet_filter = i;
}
@ -136,6 +145,9 @@ void smf_bearer_binding(smf_sess_t *sess)
if (pcc_rule->type == OGS_PCC_RULE_TYPE_INSTALL) {
ogs_pfcp_pdr_t *dl_pdr = NULL, *ul_pdr = NULL;
ogs_list_t pf_to_add_list;
ogs_list_init(&pf_to_add_list);
bearer = smf_bearer_find_by_pcc_rule_name(sess, pcc_rule->name);
if (!bearer) {
if (pcc_rule->num_of_flow == 0) {
@ -206,13 +218,6 @@ void smf_bearer_binding(smf_sess_t *sess)
} else {
ogs_assert(strcmp(bearer->pcc_rule.name, pcc_rule->name) == 0);
if (pcc_rule->num_of_flow) {
/* We'll use always 'Create new TFT'.
* Therefore, all previous flows are removed
* and replaced by the new flow */
smf_pf_remove_all(bearer);
}
if ((pcc_rule->qos.mbr.downlink &&
bearer->qos.mbr.downlink != pcc_rule->qos.mbr.downlink) ||
(pcc_rule->qos.mbr.uplink &&
@ -261,6 +266,11 @@ void smf_bearer_binding(smf_sess_t *sess)
flow->direction);
}
if (smf_pf_find_by_flow(
bearer, flow->direction, flow->description) != NULL) {
continue;
}
pf = smf_pf_add(bearer);
ogs_assert(pf);
@ -292,6 +302,8 @@ void smf_bearer_binding(smf_sess_t *sess)
smf_pf_remove(pf);
break;
}
ogs_list_add(&pf_to_add_list, pf);
}
if (bearer_created == 1) {
@ -326,7 +338,11 @@ void smf_bearer_binding(smf_sess_t *sess)
memset(&tft, 0, sizeof tft);
if (pcc_rule->num_of_flow)
encode_traffic_flow_template(&tft, bearer);
encode_traffic_flow_template(
&tft, &pf_to_add_list,
OGS_GTP_TFT_CODE_ADD_PACKET_FILTERS_TO_EXISTING_TFT);
ogs_list_empty(&pf_to_add_list);
memset(&h, 0, sizeof(ogs_gtp_header_t));
h.type = OGS_GTP_UPDATE_BEARER_REQUEST_TYPE;
@ -400,7 +416,7 @@ void smf_gtp_send_create_bearer_request(smf_bearer_t *bearer)
h.teid = sess->sgw_s5c_teid;
memset(&tft, 0, sizeof tft);
encode_traffic_flow_template(&tft, bearer);
encode_traffic_flow_template(&tft, &bearer->pf_list, OGS_GTP_TFT_CODE_CREATE_NEW_TFT);
pkbuf = smf_s5c_build_create_bearer_request(h.type, bearer, &tft);
ogs_expect_or_return(pkbuf);
@ -440,6 +456,9 @@ void smf_qos_flow_binding(smf_sess_t *sess, ogs_sbi_stream_t *stream)
if (pcc_rule->type == OGS_PCC_RULE_TYPE_INSTALL) {
ogs_pfcp_pdr_t *dl_pdr = NULL, *ul_pdr = NULL;
ogs_list_t pf_to_add_list;
ogs_list_init(&pf_to_add_list);
qos_flow = smf_qos_flow_find_by_pcc_rule_id(sess, pcc_rule->id);
if (!qos_flow) {
if (pcc_rule->num_of_flow == 0) {
@ -488,13 +507,6 @@ void smf_qos_flow_binding(smf_sess_t *sess, ogs_sbi_stream_t *stream)
ogs_assert_if_reached();
ogs_assert(strcmp(qos_flow->pcc_rule.id, pcc_rule->id) == 0);
if (pcc_rule->num_of_flow) {
/* We'll use always 'Create new TFT'.
* Therefore, all previous flows are removed
* and replaced by the new flow */
smf_pf_remove_all(qos_flow);
}
if ((pcc_rule->qos.mbr.downlink &&
qos_flow->qos.mbr.downlink != pcc_rule->qos.mbr.downlink) ||
(pcc_rule->qos.mbr.uplink &&
@ -543,6 +555,11 @@ void smf_qos_flow_binding(smf_sess_t *sess, ogs_sbi_stream_t *stream)
flow->direction);
}
if (smf_pf_find_by_flow(
qos_flow, flow->direction, flow->description) != NULL) {
continue;
}
pf = smf_pf_add(qos_flow);
ogs_assert(pf);
@ -574,6 +591,8 @@ void smf_qos_flow_binding(smf_sess_t *sess, ogs_sbi_stream_t *stream)
smf_pf_remove(pf);
break;
}
ogs_list_add(&pf_to_add_list, pf);
}
if (qos_flow_created == 1) {
@ -611,7 +630,11 @@ void smf_qos_flow_binding(smf_sess_t *sess, ogs_sbi_stream_t *stream)
memset(&tft, 0, sizeof tft);
if (pcc_rule->num_of_flow)
encode_traffic_flow_template(&tft, qos_flow);
encode_traffic_flow_template(
&tft, &pf_to_add_list,
OGS_GTP_TFT_CODE_ADD_PACKET_FILTERS_TO_EXISTING_TFT);
ogs_list_empty(&pf_to_add_list);
memset(&h, 0, sizeof(ogs_gtp_header_t));
h.type = OGS_GTP_UPDATE_BEARER_REQUEST_TYPE;

View File

@ -2177,6 +2177,21 @@ smf_pf_t *smf_pf_find_by_id(smf_bearer_t *bearer, uint8_t id)
return NULL;
}
smf_pf_t *smf_pf_find_by_flow(
smf_bearer_t *bearer, uint8_t direction, char *flow_description)
{
smf_pf_t *pf = NULL;
ogs_list_for_each(&bearer->pf_list, pf) {
if ((pf->direction == direction) &&
(!strcmp(pf->flow_description, flow_description))) {
return pf;
}
}
return NULL;
}
smf_pf_t *smf_pf_first(smf_bearer_t *bearer)
{
return ogs_list_first(&bearer->pf_list);

View File

@ -407,6 +407,8 @@ smf_pf_t *smf_pf_add(smf_bearer_t *bearer);
int smf_pf_remove(smf_pf_t *pf);
void smf_pf_remove_all(smf_bearer_t *bearer);
smf_pf_t *smf_pf_find_by_id(smf_bearer_t *smf_bearer, uint8_t id);
smf_pf_t *smf_pf_find_by_flow(
smf_bearer_t *bearer, uint8_t direction, char *flow_description);
smf_pf_t *smf_pf_first(smf_bearer_t *bearer);
smf_pf_t *smf_pf_next(smf_pf_t *pf);