[SMF] UpdatePDPContext: forward update of remote TEID+IPaddr to UPF (#1383)

* [SMF] typo fixes in commented code

* [SMF] Fix early err return handling UpdatePDPContextRequest

* [SMF] UpdatePDPContext: forward update of remote TEID+IPaddr to UPF

Updating the remote GTP-U IP address and/or TEID on the GGSN is a common
practice, used for instance by an SGSN in a UTRAN network to connect an
HNB(GW) to exchange GTP-U directly with the GGSN. It is also used in
general when doing handovers.
When receiving a UpdatePDPContext with the new address, we need to
forward the update to the UPF so that it takes it into account when
forwarding packets.

This patch only implements updating the information towards the UPF when
GTPv1C is used. Similar approach for GTPv2C (upon receival of Modify
Bearer Request) is still unimplemented.

Related: https://github.com/open5gs/open5gs/issues/1367
This commit is contained in:
Pau Espin 2022-02-23 12:21:33 +01:00 committed by GitHub
parent af3db1770f
commit 5ad1b188e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 87 additions and 11 deletions

View File

@ -299,7 +299,7 @@ void smf_gn_handle_update_pdp_context_request(
uint8_t cause_value = OGS_GTP1_CAUSE_REQUEST_ACCEPTED;
ogs_gtp1_header_t h;
ogs_pkbuf_t *pkbuf = NULL;
ogs_pfcp_pdr_t *pdr = NULL;
smf_bearer_t *bearer = NULL;
smf_ue_t *smf_ue = NULL;
@ -356,6 +356,7 @@ void smf_gn_handle_update_pdp_context_request(
ogs_gtp1_send_error_message(xact, sess->sgw_s5c_teid,
OGS_GTP1_UPDATE_PDP_CONTEXT_RESPONSE_TYPE,
OGS_GTP1_CAUSE_NON_EXISTENT);
return;
}
}
@ -386,12 +387,43 @@ void smf_gn_handle_update_pdp_context_request(
h.type = OGS_GTP1_UPDATE_PDP_CONTEXT_RESPONSE_TYPE;
h.teid = sess->sgw_s5c_teid;
pkbuf = smf_gn_build_update_pdp_context_response(h.type, sess, bearer);
ogs_expect_or_return(pkbuf);
/* Set bearer so it's accessible later when handling PFCP Session Modification Response */
xact->data = bearer;
rv = ogs_gtp1_xact_update_tx(xact, &h, pkbuf);
ogs_expect_or_return(rv == OGS_OK);
/* Update remote TEID and GTP-U IP address on the UPF. UpdatePDPContextResp
* will be sent when UPF answers back this request
*/
ogs_list_for_each(&sess->pfcp.pdr_list, pdr) {
ogs_pfcp_far_t *far = pdr->far;
ogs_assert(far);
rv = ogs_gtp_xact_commit(xact);
ogs_expect(rv == OGS_OK);
if (pdr->src_if != OGS_PFCP_INTERFACE_CORE ||
far->dst_if != OGS_PFCP_INTERFACE_ACCESS)
continue;
if (!(far->apply_action & OGS_PFCP_APPLY_ACTION_FORW))
continue;
if (pdr->id == bearer->dl_pdr->id) {
rv = ogs_pfcp_ip_to_outer_header_creation(&bearer->sgw_s5u_ip,
&far->outer_header_creation,
&far->outer_header_creation_len);
ogs_assert(rv == OGS_OK);
far->outer_header_creation.teid = bearer->sgw_s5u_teid;
}
}
rv = smf_epc_pfcp_send_session_modification_request(sess, xact,
OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_ACTIVATE,
OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED,
OGS_GTP1_CAUSE_REACTIACTION_REQUESTED);
ogs_assert(rv == OGS_OK);
/* TODO: TS 29.061: Upon reception of an UpdatePDPContextRequest from the
SGSN, the GGSN may send an Accounting Request (Interim) to the Diameter
server to update the necessary information related to this PDP context. */
/* The P-GW need not wait for the Diameter Accounting Answer message from
the Diameter server before sending the response for the triggering
signalling message (e.g. Modify Bearer Response). The P-GW may delete the
bearer if the Accounting Answer is not received from the Diameter
server.*/
}

View File

@ -361,7 +361,7 @@ int smf_gtp1_send_delete_pdp_context_response(
}
#if 0
int smf_gtp_send_update_pdp_context_request(
int smf_gtp1_send_update_pdp_context_request(
smf_bearer_t *bearer, uint8_t pti, uint8_t cause_value)
{
int rv;
@ -376,7 +376,7 @@ int smf_gtp_send_update_pdp_context_request(
sess = bearer->sess;
ogs_assert(sess);
memset(&h, 0, sizeof(ogs_gtp_header_t));
memset(&h, 0, sizeof(ogs_gtp1_header_t));
h.type = OGS_GTP1_UPDATE_PDP_CONTEXT_REQUEST_TYPE;
h.teid = sess->sgw_s5c_teid;
@ -395,6 +395,38 @@ int smf_gtp_send_update_pdp_context_request(
}
#endif
int smf_gtp1_send_update_pdp_context_response(
smf_bearer_t *bearer, ogs_gtp_xact_t *xact)
{
int rv;
ogs_gtp1_header_t h;
ogs_pkbuf_t *pkbuf = NULL;
smf_sess_t *sess = NULL;
ogs_assert(bearer);
ogs_assert(xact);
sess = bearer->sess;
ogs_assert(sess);
memset(&h, 0, sizeof(ogs_gtp1_header_t));
h.type = OGS_GTP1_UPDATE_PDP_CONTEXT_RESPONSE_TYPE;
h.teid = sess->sgw_s5c_teid;
pkbuf = smf_gn_build_update_pdp_context_response(
h.type, sess, bearer);
ogs_expect_or_return_val(pkbuf, OGS_ERROR);
rv = ogs_gtp1_xact_update_tx(xact, &h, pkbuf);
ogs_expect_or_return_val(rv == OGS_OK, OGS_ERROR);
rv = ogs_gtp_xact_commit(xact);
ogs_expect(rv == OGS_OK);
return rv;
}
int smf_gtp_send_create_session_response(
smf_sess_t *sess, ogs_gtp_xact_t *xact)
{

View File

@ -33,8 +33,10 @@ int smf_gtp1_send_create_pdp_context_response(
smf_sess_t *sess, ogs_gtp_xact_t *xact);
int smf_gtp1_send_delete_pdp_context_response(
smf_sess_t *sess, ogs_gtp_xact_t *xact);
int smf_gtp_send_update_pdp_context_request(
int smf_gtp1_send_update_pdp_context_request(
smf_bearer_t *bearer, uint8_t pti, uint8_t cause_value);
int smf_gtp1_send_update_pdp_context_response(
smf_bearer_t *bearer, ogs_gtp_xact_t *xact);
int smf_gtp_send_create_session_response(
smf_sess_t *sess, ogs_gtp_xact_t *xact);

View File

@ -1105,7 +1105,13 @@ void smf_epc_n4_handle_session_modification_response(
}
} else if (flags & OGS_PFCP_MODIFY_ACTIVATE) {
/* Nothing */
/* SMF send Update PDP Context Response (GTPv1C) to SGSN */
if (gtp_xact->gtp_version == 1) {
bearer = gtp_xact->data;
smf_gtp1_send_update_pdp_context_response(bearer, gtp_xact);
} else {
/* TODO: SMF send Modify Bearer Response (GTPv2C) to SGWC */
}
}
}

View File

@ -423,6 +423,10 @@ void smf_s5c_handle_modify_bearer_request(
ogs_debug(" SGW_S5C_TEID[0x%x] SMF_N4_TEID[0x%x]",
sess->sgw_s5c_teid, sess->smf_n4_teid);
/* TODO: Update remote GTP-U IP addr + TEID in the UPF through PFCP, similar
* to what is done in smf_gn_handle_update_pdp_context_request()
*/
memset(&h, 0, sizeof(ogs_gtp_header_t));
h.type = OGS_GTP_MODIFY_BEARER_RESPONSE_TYPE;
h.teid = sess->sgw_s5c_teid;