[PFCP] Implement the Restoration Indication

This commit is contained in:
Sukchan Lee 2023-04-15 18:54:03 +09:00
parent 642d9e2e18
commit d2e2a58232
33 changed files with 639 additions and 400 deletions

View File

@ -446,17 +446,15 @@ bool ogs_pfcp_build_created_pdr(
ogs_assert(pdr);
if (ogs_pfcp_self()->up_function_features.ftup) {
if (pdr->f_teid_len) {
memcpy(&pdrbuf[i].f_teid, &pdr->f_teid, pdr->f_teid_len);
pdrbuf[i].f_teid.teid = htobe32(pdr->f_teid.teid);
if (pdr->f_teid_len) {
memcpy(&pdrbuf[i].f_teid, &pdr->f_teid, pdr->f_teid_len);
pdrbuf[i].f_teid.teid = htobe32(pdr->f_teid.teid);
message->local_f_teid.presence = 1;
message->local_f_teid.data = &pdrbuf[i].f_teid;
message->local_f_teid.len = pdr->f_teid_len;
message->local_f_teid.presence = 1;
message->local_f_teid.data = &pdrbuf[i].f_teid;
message->local_f_teid.len = pdr->f_teid_len;
pdr_presence = true;
}
pdr_presence = true;
}
if (pdr_presence == true) {

View File

@ -27,19 +27,23 @@ static int context_initialized = 0;
static OGS_POOL(ogs_pfcp_node_pool, ogs_pfcp_node_t);
static OGS_POOL(ogs_pfcp_sess_pool, ogs_pfcp_sess_t);
static OGS_POOL(ogs_pfcp_pdr_pool, ogs_pfcp_pdr_t);
static OGS_POOL(ogs_pfcp_pdr_teid_pool, ogs_pool_id_t);
static OGS_POOL(ogs_pfcp_far_pool, ogs_pfcp_far_t);
static OGS_POOL(ogs_pfcp_urr_pool, ogs_pfcp_urr_t);
static OGS_POOL(ogs_pfcp_qer_pool, ogs_pfcp_qer_t);
static OGS_POOL(ogs_pfcp_bar_pool, ogs_pfcp_bar_t);
static OGS_POOL(ogs_pfcp_pdr_pool, ogs_pfcp_pdr_t);
static OGS_POOL(ogs_pfcp_pdr_teid_pool, ogs_pool_id_t);
static ogs_pool_id_t *pdr_random_to_index;
static OGS_POOL(ogs_pfcp_rule_pool, ogs_pfcp_rule_t);
static OGS_POOL(ogs_pfcp_dev_pool, ogs_pfcp_dev_t);
static OGS_POOL(ogs_pfcp_subnet_pool, ogs_pfcp_subnet_t);
static OGS_POOL(ogs_pfcp_rule_pool, ogs_pfcp_rule_t);
void ogs_pfcp_context_init(void)
{
int i;
ogs_assert(context_initialized == 0);
/* Initialize SMF context */
@ -53,11 +57,6 @@ void ogs_pfcp_context_init(void)
ogs_pool_init(&ogs_pfcp_sess_pool, ogs_app()->pool.sess);
ogs_pool_init(&ogs_pfcp_pdr_pool,
ogs_app()->pool.sess * OGS_MAX_NUM_OF_PDR);
ogs_pool_init(&ogs_pfcp_pdr_teid_pool,
ogs_app()->pool.sess * OGS_MAX_NUM_OF_PDR);
ogs_pool_random_id_generate(&ogs_pfcp_pdr_teid_pool);
ogs_pool_init(&ogs_pfcp_far_pool,
ogs_app()->pool.sess * OGS_MAX_NUM_OF_FAR);
ogs_pool_init(&ogs_pfcp_urr_pool,
@ -67,6 +66,17 @@ void ogs_pfcp_context_init(void)
ogs_pool_init(&ogs_pfcp_bar_pool,
ogs_app()->pool.sess * OGS_MAX_NUM_OF_BAR);
ogs_pool_init(&ogs_pfcp_pdr_pool,
ogs_app()->pool.sess * OGS_MAX_NUM_OF_PDR);
ogs_pool_init(&ogs_pfcp_pdr_teid_pool, ogs_pfcp_pdr_pool.size);
ogs_pool_random_id_generate(&ogs_pfcp_pdr_teid_pool);
pdr_random_to_index = ogs_calloc(
sizeof(ogs_pool_id_t), ogs_pfcp_pdr_pool.size);
ogs_assert(pdr_random_to_index);
for (i = 0; i < ogs_pfcp_pdr_pool.size; i++)
pdr_random_to_index[ogs_pfcp_pdr_teid_pool.array[i]] = i;
ogs_pool_init(&ogs_pfcp_rule_pool,
ogs_app()->pool.sess *
OGS_MAX_NUM_OF_PDR * OGS_MAX_NUM_OF_FLOW_IN_PDR);
@ -102,9 +112,11 @@ void ogs_pfcp_context_final(void)
ogs_pool_final(&ogs_pfcp_subnet_pool);
ogs_pool_final(&ogs_pfcp_rule_pool);
ogs_pool_final(&ogs_pfcp_sess_pool);
ogs_pool_final(&ogs_pfcp_pdr_pool);
ogs_pool_final(&ogs_pfcp_pdr_teid_pool);
ogs_free(pdr_random_to_index);
ogs_pool_final(&ogs_pfcp_sess_pool);
ogs_pool_final(&ogs_pfcp_far_pool);
ogs_pool_final(&ogs_pfcp_urr_pool);
ogs_pool_final(&ogs_pfcp_qer_pool);
@ -955,12 +967,88 @@ ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_or_add(
return pdr;
}
void ogs_pfcp_pdr_swap_teid(ogs_pfcp_pdr_t *pdr)
{
int i = 0;
ogs_assert(pdr);
ogs_assert(pdr->f_teid.teid > 0 &&
pdr->f_teid.teid <= ogs_pfcp_pdr_teid_pool.size);
/* Find out the Array Index for the restored TEID. */
i = pdr_random_to_index[pdr->f_teid.teid];
ogs_assert(i < ogs_pfcp_pdr_teid_pool.size);
ogs_assert(pdr->teid_node);
/*
* If SWAP has already done this, it will not try this again.
* This situation can occur when multiple PDRs are restored
* with the same TEID.
*/
if (pdr->f_teid.teid == ogs_pfcp_pdr_teid_pool.array[i]) {
ogs_pfcp_pdr_teid_pool.array[i] = *(pdr->teid_node);
*(pdr->teid_node) = pdr->f_teid.teid;
}
}
void ogs_pfcp_object_teid_hash_set(
ogs_pfcp_object_type_e type, ogs_pfcp_pdr_t *pdr)
ogs_pfcp_object_type_e type, ogs_pfcp_pdr_t *pdr,
bool restoration_indication)
{
ogs_assert(type);
ogs_assert(pdr);
if (ogs_pfcp_self()->up_function_features.ftup && pdr->f_teid.ch) {
ogs_pfcp_pdr_t *choosed_pdr = NULL;
if (pdr->f_teid.chid) {
choosed_pdr = ogs_pfcp_pdr_find_by_choose_id(
pdr->sess, pdr->f_teid.choose_id);
if (!choosed_pdr) {
pdr->chid = true;
pdr->choose_id = pdr->f_teid.choose_id;
}
}
if (choosed_pdr) {
pdr->f_teid_len = choosed_pdr->f_teid_len;
memcpy(&pdr->f_teid, &choosed_pdr->f_teid, pdr->f_teid_len);
} else {
ogs_gtpu_resource_t *resource = NULL;
resource = ogs_pfcp_find_gtpu_resource(
&ogs_gtp_self()->gtpu_resource_list,
pdr->dnn, OGS_PFCP_INTERFACE_ACCESS);
if (resource) {
ogs_assert(
(resource->info.v4 && pdr->f_teid.ipv4) ||
(resource->info.v6 && pdr->f_teid.ipv6));
ogs_assert(OGS_OK ==
ogs_pfcp_user_plane_ip_resource_info_to_f_teid(
&resource->info, &pdr->f_teid, &pdr->f_teid_len));
if (resource->info.teidri)
pdr->f_teid.teid = OGS_PFCP_GTPU_INDEX_TO_TEID(
pdr->teid, resource->info.teidri,
resource->info.teid_range);
else
pdr->f_teid.teid = pdr->teid;
} else {
ogs_assert(
(ogs_gtp_self()->gtpu_addr && pdr->f_teid.ipv4) ||
(ogs_gtp_self()->gtpu_addr6 && pdr->f_teid.ipv6));
ogs_assert(OGS_OK ==
ogs_pfcp_sockaddr_to_f_teid(
pdr->f_teid.ipv4 ?
ogs_gtp_self()->gtpu_addr : NULL,
pdr->f_teid.ipv6 ?
ogs_gtp_self()->gtpu_addr6 : NULL,
&pdr->f_teid, &pdr->f_teid_len));
pdr->f_teid.teid = pdr->teid;
}
}
}
if (pdr->hash.teid.len)
ogs_hash_set(self.object_teid_hash,
&pdr->hash.teid.key, pdr->hash.teid.len, NULL);

View File

@ -401,8 +401,11 @@ ogs_pfcp_pdr_t *ogs_pfcp_pdr_find(
ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_or_add(
ogs_pfcp_sess_t *sess, ogs_pfcp_pdr_id_t id);
void ogs_pfcp_pdr_swap_teid(ogs_pfcp_pdr_t *pdr);
void ogs_pfcp_object_teid_hash_set(
ogs_pfcp_object_type_e type, ogs_pfcp_pdr_t *pdr);
ogs_pfcp_object_type_e type, ogs_pfcp_pdr_t *pdr,
bool restoration_indication);
ogs_pfcp_object_t *ogs_pfcp_object_find_by_teid(uint32_t teid);
int ogs_pfcp_object_count_by_teid(ogs_pfcp_sess_t *sess, uint32_t teid);

View File

@ -320,6 +320,7 @@ bool ogs_pfcp_up_handle_error_indication(
ogs_pfcp_pdr_t *ogs_pfcp_handle_create_pdr(ogs_pfcp_sess_t *sess,
ogs_pfcp_tlv_create_pdr_t *message,
ogs_pfcp_sereq_flags_t *sereq_flags,
uint8_t *cause_value, uint8_t *offending_ie_value)
{
ogs_pfcp_pdr_t *pdr = NULL;
@ -376,6 +377,18 @@ ogs_pfcp_pdr_t *ogs_pfcp_handle_create_pdr(ogs_pfcp_sess_t *sess,
*offending_ie_value = OGS_PFCP_F_TEID_TYPE;
return NULL;
}
if (f_teid.ch == 0) {
if (sereq_flags && sereq_flags->restoration_indication == 1) {
f_teid.teid = be32toh(f_teid.teid);
if (ogs_pfcp_object_find_by_teid(f_teid.teid)) {
ogs_error("TEID:%x had already been allocated", f_teid.teid);
*cause_value = OGS_PFCP_CAUSE_INVALID_F_TEID_ALLOCATION_OPTION;
*offending_ie_value = OGS_PFCP_F_TEID_TYPE;
return NULL;
}
}
}
}
pdr->src_if = message->pdi.source_interface.u8;
@ -398,7 +411,6 @@ ogs_pfcp_pdr_t *ogs_pfcp_handle_create_pdr(ogs_pfcp_sess_t *sess,
if (sdf_filter.bid) {
oppsite_direction_rule = ogs_pfcp_rule_find_by_sdf_filter_id(
sess, sdf_filter.sdf_filter_id);
}
if (!oppsite_direction_rule && !sdf_filter.fd) {

View File

@ -53,6 +53,7 @@ bool ogs_pfcp_up_handle_error_indication(
ogs_pfcp_pdr_t *ogs_pfcp_handle_create_pdr(ogs_pfcp_sess_t *sess,
ogs_pfcp_tlv_create_pdr_t *message,
ogs_pfcp_sereq_flags_t *sereq_flags,
uint8_t *cause_value, uint8_t *offending_ie_value);
ogs_pfcp_pdr_t *ogs_pfcp_handle_created_pdr(ogs_pfcp_sess_t *sess,
ogs_pfcp_tlv_created_pdr_t *message,

View File

@ -20,7 +20,7 @@
/*******************************************************************************
* This file had been created by pfcp-tlv.py script v0.1.0
* Please do not modify this file but regenerate it via script.
* Created on: 2023-03-05 22:26:11.716006 by acetcom
* Created on: 2023-04-09 20:37:00.518388 by acetcom
* from 29244-h71-modified.docx
******************************************************************************/
@ -1546,10 +1546,10 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_cp_pfcp_entity_ip_address =
ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcpsereq_flags =
{
OGS_TLV_VAR_STR,
OGS_TLV_UINT8,
"PFCPSEReq-Flags",
OGS_PFCP_PFCPSEREQ_FLAGS_TYPE,
0,
1,
0,
sizeof(ogs_pfcp_tlv_pfcpsereq_flags_t),
{ NULL }

View File

@ -20,7 +20,7 @@
/*******************************************************************************
* This file had been created by pfcp-tlv.py script v0.1.0
* Please do not modify this file but regenerate it via script.
* Created on: 2023-03-05 22:26:11.698310 by acetcom
* Created on: 2023-04-09 20:37:00.506639 by acetcom
* from 29244-h71-modified.docx
******************************************************************************/
@ -903,7 +903,7 @@ typedef ogs_tlv_uint32_t ogs_pfcp_tlv_quota_validity_time_t;
typedef ogs_tlv_octet_t ogs_pfcp_tlv_number_of_reports_t;
typedef ogs_tlv_octet_t ogs_pfcp_tlv_pfcpasrsp_flags_t;
typedef ogs_tlv_octet_t ogs_pfcp_tlv_cp_pfcp_entity_ip_address_t;
typedef ogs_tlv_octet_t ogs_pfcp_tlv_pfcpsereq_flags_t;
typedef ogs_tlv_uint8_t ogs_pfcp_tlv_pfcpsereq_flags_t;
typedef ogs_tlv_octet_t ogs_pfcp_tlv_ip_multicast_address_t;
typedef ogs_tlv_octet_t ogs_pfcp_tlv_source_ip_address_t;
typedef ogs_tlv_octet_t ogs_pfcp_tlv_packet_rate_status_t;

View File

@ -519,6 +519,7 @@ type_list["Paging Policy Indicator"]["size"] = 1 # Type 158
type_list["PFCPSRReq-Flags"]["size"] = 1 # Type 161
type_list["PFCPAUReq-Flags"]["size"] = 1 # Type 162
type_list["Quota Validity Time"]["size"] = 4 # Type 181
type_list["PFCPSEReq-Flags"]["size"] = 1 # Type 186
type_list["Data Status"]["size"] = 1 # Type 260
f = open(outdir + 'message.h', 'w')

View File

@ -1651,6 +1651,28 @@ int16_t ogs_pfcp_build_user_id(
ogs_tlv_octet_t *octet, ogs_pfcp_user_id_t *user_id,
void *data, int data_len);
/*
* 8.2.136 PFCPSEReq-Flags
*
* The following bits within Octet 5 shall indicate:
* - Bit 1 RESTI (Restoration Indication): if this bit is set to "1",
* it indicates to the UP function that the PFCP session to be established is
* to restore an existing PFCP session.
* - Bit 2 SUMPC (Stop of Usage Measurement to Pause Charging):
* if this bit is set to "1", it indicates that the UP function shall
* stop the usage measurement for all URRs with the "ASPOC" flag set to "1".
*/
typedef struct ogs_pfcp_sereq_flags_s {
union {
struct {
ED3(uint8_t spare:6;,
uint8_t stop_of_usage_measurement_to_pause_charging:1;,
uint8_t restoration_indication:1;)
};
uint8_t value;
};
} __attribute__ ((packed)) ogs_pfcp_sereq_flags_t;
#ifdef __cplusplus
}
#endif

View File

@ -78,6 +78,9 @@ typedef struct ogs_pfcp_xact_s {
bool epc; /**< EPC or 5GC */
#define OGS_PFCP_CREATE_RESTORATION_INDICATION ((uint64_t)1<<0)
uint64_t create_flags;
#define OGS_PFCP_MODIFY_SESSION ((uint64_t)1<<0)
#define OGS_PFCP_MODIFY_DL_ONLY ((uint64_t)1<<1)
#define OGS_PFCP_MODIFY_UL_ONLY ((uint64_t)1<<2)
@ -110,7 +113,6 @@ typedef struct ogs_pfcp_xact_s {
#define OGS_PFCP_MODIFY_URR_TIME_QUOTA ((uint64_t)1<<29)
#define OGS_PFCP_MODIFY_URR_VOLUME_THRESH ((uint64_t)1<<30)
#define OGS_PFCP_MODIFY_URR_TIME_THRESH ((uint64_t)1<<31)
uint64_t modify_flags;
#define OGS_PFCP_DELETE_TRIGGER_LOCAL_INITIATED 1

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -238,7 +238,8 @@ int sgwc_pfcp_send_bearer_to_modify_list(
}
int sgwc_pfcp_send_session_establishment_request(
sgwc_sess_t *sess, ogs_gtp_xact_t *gtp_xact, ogs_pkbuf_t *gtpbuf)
sgwc_sess_t *sess, ogs_gtp_xact_t *gtp_xact, ogs_pkbuf_t *gtpbuf,
uint64_t flags)
{
int rv;
ogs_pkbuf_t *sxabuf = NULL;
@ -262,9 +263,40 @@ int sgwc_pfcp_send_session_establishment_request(
}
}
xact->local_seid = sess->sgwc_sxa_seid;
xact->create_flags = flags;
memset(&h, 0, sizeof(ogs_pfcp_header_t));
h.type = OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE;
/*
* 7.2.2.4.2 Conditions for Sending SEID=0 in PFCP Header
*
* If a peer's SEID is not available, the SEID field shall still be present
* in the header and its value shall be set to "0" in the following messages:
*
* - PFCP Session Establishment Request message on Sxa/Sxb/Sxc/N4;
*
* - If a node receives a message for which it has no session, i.e.
* if SEID in the PFCP header is not known, it shall respond
* with "Session context not found" cause in the corresponding
* response message to the sender, the SEID used in the PFCP header
* in the response message shall be then set to "0";
*
* - If a node receives a request message containing protocol error,
* e.g. Mandatory IE missing, which requires the receiver
* to reject the message as specified in clause 7.6, it shall reject
* the request message. For the response message, the node should look up
* the remote peer's SEID and accordingly set SEID in the PFCP header
* and the message cause code. As an implementation option,
* the node may not look up the remote peer's SEID and
* set the PFCP header SEID to "0" in the response message.
* However in this case, the cause value shall not be set
* to "Session not found".
*
* - When the UP function sends PFCP Session Report Request message
* over N4 towards another SMF or another PFCP entity in the SMF
* as specified in clause 5.22.2 and clause 5.22.3.
*/
h.seid = sess->sgwu_sxa_seid;
sxabuf = sgwc_sxa_build_session_establishment_request(h.type, sess);

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -33,7 +33,8 @@ int sgwc_pfcp_send_bearer_to_modify_list(
sgwc_sess_t *sess, ogs_pfcp_xact_t *xact);
int sgwc_pfcp_send_session_establishment_request(
sgwc_sess_t *sess, ogs_gtp_xact_t *gtp_xact, ogs_pkbuf_t *gtpbuf);
sgwc_sess_t *sess, ogs_gtp_xact_t *gtp_xact, ogs_pkbuf_t *gtpbuf,
uint64_t flags);
int sgwc_pfcp_send_session_modification_request(
sgwc_sess_t *sess, ogs_gtp_xact_t *gtp_xact,

View File

@ -20,6 +20,7 @@
#include "pfcp-path.h"
#include "sxa-handler.h"
static void pfcp_restoration(ogs_pfcp_node_t *node);
static void node_timeout(ogs_pfcp_xact_t *xact, void *data);
void sgwc_pfcp_state_initial(ogs_fsm_t *s, sgwc_event_t *e)
@ -188,6 +189,7 @@ void sgwc_pfcp_state_associated(ogs_fsm_t *s, sgwc_event_t *e)
ogs_pfcp_send_heartbeat_request(node, node_timeout));
if (node->restoration_required == true) {
pfcp_restoration(node);
node->restoration_required = false;
ogs_error("PFCP restoration");
}
@ -220,11 +222,56 @@ void sgwc_pfcp_state_associated(ogs_fsm_t *s, sgwc_event_t *e)
ogs_expect(true ==
ogs_pfcp_handle_heartbeat_request(node, xact,
&message->pfcp_heartbeat_request));
if (node->restoration_required == true) {
if (node->t_association) {
/*
* node->t_association that the PFCP entity attempts an association.
*
* In this case, even if Remote PFCP entity is restarted,
* PFCP restoration must be performed after PFCP association.
*
* Otherwise, Session related PFCP cannot be initiated
* because the peer PFCP entity is in a de-associated state.
*/
OGS_FSM_TRAN(s, sgwc_pfcp_state_will_associate);
} else {
/*
* If the peer PFCP entity is performing the association,
* Restoration can be performed immediately.
*/
pfcp_restoration(node);
node->restoration_required = false;
ogs_error("PFCP restoration");
}
}
break;
case OGS_PFCP_HEARTBEAT_RESPONSE_TYPE:
ogs_expect(true ==
ogs_pfcp_handle_heartbeat_response(node, xact,
&message->pfcp_heartbeat_response));
if (node->restoration_required == true) {
/*
* node->t_association that the PFCP entity attempts an association.
*
* In this case, even if Remote PFCP entity is restarted,
* PFCP restoration must be performed after PFCP association.
*
* Otherwise, Session related PFCP cannot be initiated
* because the peer PFCP entity is in a de-associated state.
*/
if (node->t_association) {
OGS_FSM_TRAN(s, sgwc_pfcp_state_will_associate);
} else {
/*
* If the peer PFCP entity is performing the association,
* Restoration can be performed immediately.
*/
pfcp_restoration(node);
node->restoration_required = false;
ogs_error("PFCP restoration");
}
}
break;
case OGS_PFCP_ASSOCIATION_SETUP_REQUEST_TYPE:
ogs_warn("PFCP[REQ] has already been associated [%s]:%d",
@ -243,9 +290,24 @@ void sgwc_pfcp_state_associated(ogs_fsm_t *s, sgwc_event_t *e)
case OGS_PFCP_SESSION_ESTABLISHMENT_RESPONSE_TYPE:
if (!message->h.seid_presence) ogs_error("No SEID");
sgwc_sxa_handle_session_establishment_response(
sess, xact, e->gtp_message,
&message->pfcp_session_establishment_response);
if ((xact->create_flags &
OGS_PFCP_CREATE_RESTORATION_INDICATION)) {
ogs_pfcp_session_establishment_response_t *rsp = NULL;
ogs_pfcp_f_seid_t *up_f_seid = NULL;
rsp = &message->pfcp_session_establishment_response;
if (rsp->up_f_seid.presence == 0) {
ogs_error("No UP F-SEID");
break;
}
up_f_seid = rsp->up_f_seid.data;
ogs_assert(up_f_seid);
sess->sgwu_sxa_seid = be64toh(up_f_seid->seid);
} else {
sgwc_sxa_handle_session_establishment_response(
sess, xact, e->gtp_message,
&message->pfcp_session_establishment_response);
}
break;
case OGS_PFCP_SESSION_MODIFICATION_RESPONSE_TYPE:
@ -326,6 +388,29 @@ void sgwc_pfcp_state_exception(ogs_fsm_t *s, sgwc_event_t *e)
}
}
static void pfcp_restoration(ogs_pfcp_node_t *node)
{
sgwc_ue_t *sgwc_ue = NULL;
ogs_list_for_each(&sgwc_self()->sgw_ue_list, sgwc_ue) {
sgwc_sess_t *sess = NULL;
ogs_assert(sgwc_ue);
ogs_list_for_each(&sgwc_ue->sess_list, sess) {
ogs_assert(sess);
if (node == sess->pfcp_node) {
ogs_info("UE IMSI[%s] APN[%s]",
sgwc_ue->imsi_bcd, sess->session.name);
ogs_assert(OGS_OK ==
sgwc_pfcp_send_session_establishment_request(
sess, NULL, NULL,
OGS_PFCP_CREATE_RESTORATION_INDICATION));
}
}
}
}
static void node_timeout(ogs_pfcp_xact_t *xact, void *data)
{
int rv;

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -234,6 +234,8 @@ void sgwc_s11_handle_create_session_request(
sess = sgwc_sess_add(sgwc_ue, apn);
ogs_assert(sess);
ogs_info("UE IMSI[%s] APN[%s]", sgwc_ue->imsi_bcd, sess->session.name);
/* Set User Location Information */
if (req->user_location_information.presence == 1) {
decoded = ogs_gtp2_parse_uli(&uli, &req->user_location_information);
@ -376,7 +378,8 @@ void sgwc_s11_handle_create_session_request(
sgwc_ue->mme_s11_teid, sgwc_ue->sgw_s11_teid);
ogs_assert(OGS_OK ==
sgwc_pfcp_send_session_establishment_request(sess, s11_xact, gtpbuf));
sgwc_pfcp_send_session_establishment_request(
sess, s11_xact, gtpbuf, 0));
}
void sgwc_s11_handle_modify_bearer_request(

View File

@ -255,7 +255,10 @@ sgwu_sess_t *sgwu_sess_add_by_message(ogs_pfcp_message_t *message)
sess = sgwu_sess_find_by_sgwc_sxa_f_seid(f_seid);
if (!sess) {
sess = sgwu_sess_add(f_seid);
if (!sess) return NULL;
if (!sess) {
ogs_error("No Session Context");
return NULL;
}
}
ogs_assert(sess);

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -203,6 +203,8 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
ogs_assert(pdr);
break;
case OGS_PFCP_OBJ_SESS_TYPE:
/* SGWU does not use SESS TYPE */
ogs_assert_if_reached();
pfcp_sess = (ogs_pfcp_sess_t *)pfcp_object;
ogs_assert(pfcp_sess);

View File

@ -205,7 +205,6 @@ int sgwu_pfcp_send_session_modification_response(
ogs_pfcp_header_t h;
ogs_assert(xact);
ogs_assert(created_pdr);
memset(&h, 0, sizeof(ogs_pfcp_header_t));
h.type = OGS_PFCP_SESSION_MODIFICATION_RESPONSE_TYPE;

View File

@ -277,12 +277,9 @@ void sgwu_pfcp_state_associated(ogs_fsm_t *s, sgwu_event_t *e)
&message->pfcp_association_setup_response);
break;
case OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE:
if (message->h.seid_presence && message->h.seid == 0) {
ogs_expect(!sess);
sess = sgwu_sess_add_by_message(message);
if (sess)
OGS_SETUP_PFCP_NODE(sess, node);
}
sess = sgwu_sess_add_by_message(message);
if (sess)
OGS_SETUP_PFCP_NODE(sess, node);
sgwu_sxa_handle_session_establishment_request(
sess, xact, &message->pfcp_session_establishment_request);
break;

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -33,6 +33,9 @@ void sgwu_sxa_handle_session_establishment_request(
uint8_t offending_ie_value = 0;
int i;
ogs_pfcp_sereq_flags_t sereq_flags;
bool restoration_indication = false;
ogs_assert(xact);
ogs_assert(req);
@ -48,9 +51,16 @@ void sgwu_sxa_handle_session_establishment_request(
return;
}
/* PFCPSEReq-Flags */
memset(&sereq_flags, 0, sizeof(sereq_flags));
if (req->pfcpsereq_flags.presence == 1) {
sereq_flags.value = req->pfcpsereq_flags.u8;
}
for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) {
created_pdr[i] = ogs_pfcp_handle_create_pdr(&sess->pfcp,
&req->create_pdr[i], &cause_value, &offending_ie_value);
&req->create_pdr[i], &sereq_flags,
&cause_value, &offending_ie_value);
if (created_pdr[i] == NULL)
break;
}
@ -79,6 +89,18 @@ void sgwu_sxa_handle_session_establishment_request(
if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED)
goto cleanup;
/* PFCPSEReq-Flags */
if (sereq_flags.restoration_indication == 1) {
for (i = 0; i < num_of_created_pdr; i++) {
pdr = created_pdr[i];
ogs_assert(pdr);
if (pdr->f_teid_len)
ogs_pfcp_pdr_swap_teid(pdr);
}
restoration_indication = true;
}
/* Setup GTP Node */
ogs_list_for_each(&sess->pfcp.far_list, far) {
ogs_assert(OGS_ERROR != ogs_pfcp_setup_far_gtpu_node(far));
@ -86,70 +108,14 @@ void sgwu_sxa_handle_session_establishment_request(
ogs_pfcp_far_f_teid_hash_set(far);
}
/* Setup TEID Hash */
for (i = 0; i < num_of_created_pdr; i++) {
pdr = created_pdr[i];
ogs_assert(pdr);
if (pdr->f_teid_len) {
ogs_pfcp_object_type_e type = OGS_PFCP_OBJ_PDR_TYPE;
if (ogs_pfcp_self()->up_function_features.ftup &&
pdr->f_teid.ch) {
ogs_pfcp_pdr_t *choosed_pdr = NULL;
if (pdr->f_teid.chid) {
type = OGS_PFCP_OBJ_SESS_TYPE;
choosed_pdr = ogs_pfcp_pdr_find_by_choose_id(
&sess->pfcp, pdr->f_teid.choose_id);
if (!choosed_pdr) {
pdr->chid = true;
pdr->choose_id = pdr->f_teid.choose_id;
}
}
if (choosed_pdr) {
pdr->f_teid_len = choosed_pdr->f_teid_len;
memcpy(&pdr->f_teid, &choosed_pdr->f_teid, pdr->f_teid_len);
} else {
ogs_gtpu_resource_t *resource = NULL;
resource = ogs_pfcp_find_gtpu_resource(
&ogs_gtp_self()->gtpu_resource_list,
pdr->apn, OGS_PFCP_INTERFACE_ACCESS);
if (resource) {
ogs_assert(
(resource->info.v4 && pdr->f_teid.ipv4) ||
(resource->info.v6 && pdr->f_teid.ipv6));
ogs_assert(OGS_OK ==
ogs_pfcp_user_plane_ip_resource_info_to_f_teid(
&resource->info, &pdr->f_teid, &pdr->f_teid_len));
if (resource->info.teidri)
pdr->f_teid.teid = OGS_PFCP_GTPU_INDEX_TO_TEID(
pdr->teid, resource->info.teidri,
resource->info.teid_range);
else
pdr->f_teid.teid = pdr->teid;
} else {
ogs_assert(
(ogs_gtp_self()->gtpu_addr && pdr->f_teid.ipv4) ||
(ogs_gtp_self()->gtpu_addr6 && pdr->f_teid.ipv6));
ogs_assert(OGS_OK ==
ogs_pfcp_sockaddr_to_f_teid(
pdr->f_teid.ipv4 ?
ogs_gtp_self()->gtpu_addr : NULL,
pdr->f_teid.ipv6 ?
ogs_gtp_self()->gtpu_addr6 : NULL,
&pdr->f_teid, &pdr->f_teid_len));
pdr->f_teid.teid = pdr->teid;
}
}
}
ogs_pfcp_object_teid_hash_set(type, pdr);
}
/* Setup TEID Hash */
if (pdr->f_teid_len)
ogs_pfcp_object_teid_hash_set(
OGS_PFCP_OBJ_PDR_TYPE, pdr, restoration_indication);
}
/* Send Buffered Packet to gNB */
@ -159,9 +125,15 @@ void sgwu_sxa_handle_session_establishment_request(
}
}
ogs_assert(OGS_OK ==
sgwu_pfcp_send_session_establishment_response(
xact, sess, created_pdr, num_of_created_pdr));
if (restoration_indication == true ||
ogs_pfcp_self()->up_function_features.ftup == 0)
ogs_assert(OGS_OK ==
sgwu_pfcp_send_session_establishment_response(
xact, sess, NULL, 0));
else
ogs_assert(OGS_OK ==
sgwu_pfcp_send_session_establishment_response(
xact, sess, created_pdr, num_of_created_pdr));
return;
cleanup:
@ -200,7 +172,7 @@ void sgwu_sxa_handle_session_modification_request(
for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) {
created_pdr[i] = ogs_pfcp_handle_create_pdr(&sess->pfcp,
&req->create_pdr[i], &cause_value, &offending_ie_value);
&req->create_pdr[i], NULL, &cause_value, &offending_ie_value);
if (created_pdr[i] == NULL)
break;
}
@ -301,70 +273,13 @@ void sgwu_sxa_handle_session_modification_request(
ogs_pfcp_far_f_teid_hash_set(far);
}
/* Setup TEID Hash */
for (i = 0; i < num_of_created_pdr; i++) {
pdr = created_pdr[i];
ogs_assert(pdr);
if (pdr->f_teid_len) {
ogs_pfcp_object_type_e type = OGS_PFCP_OBJ_PDR_TYPE;
if (ogs_pfcp_self()->up_function_features.ftup &&
pdr->f_teid.ch) {
ogs_pfcp_pdr_t *choosed_pdr = NULL;
if (pdr->f_teid.chid) {
type = OGS_PFCP_OBJ_SESS_TYPE;
choosed_pdr = ogs_pfcp_pdr_find_by_choose_id(
&sess->pfcp, pdr->f_teid.choose_id);
if (!choosed_pdr) {
pdr->chid = true;
pdr->choose_id = pdr->f_teid.choose_id;
}
}
if (choosed_pdr) {
pdr->f_teid_len = choosed_pdr->f_teid_len;
memcpy(&pdr->f_teid, &choosed_pdr->f_teid, pdr->f_teid_len);
} else {
ogs_gtpu_resource_t *resource = NULL;
resource = ogs_pfcp_find_gtpu_resource(
&ogs_gtp_self()->gtpu_resource_list,
pdr->apn, OGS_PFCP_INTERFACE_ACCESS);
if (resource) {
ogs_assert(
(resource->info.v4 && pdr->f_teid.ipv4) ||
(resource->info.v6 && pdr->f_teid.ipv6));
ogs_assert(OGS_OK ==
ogs_pfcp_user_plane_ip_resource_info_to_f_teid(
&resource->info, &pdr->f_teid, &pdr->f_teid_len));
if (resource->info.teidri)
pdr->f_teid.teid = OGS_PFCP_GTPU_INDEX_TO_TEID(
pdr->teid, resource->info.teidri,
resource->info.teid_range);
else
pdr->f_teid.teid = pdr->teid;
} else {
ogs_assert(
(ogs_gtp_self()->gtpu_addr && pdr->f_teid.ipv4) ||
(ogs_gtp_self()->gtpu_addr6 && pdr->f_teid.ipv6));
ogs_assert(OGS_OK ==
ogs_pfcp_sockaddr_to_f_teid(
pdr->f_teid.ipv4 ?
ogs_gtp_self()->gtpu_addr : NULL,
pdr->f_teid.ipv6 ?
ogs_gtp_self()->gtpu_addr6 : NULL,
&pdr->f_teid, &pdr->f_teid_len));
pdr->f_teid.teid = pdr->teid;
}
}
}
ogs_pfcp_object_teid_hash_set(type, pdr);
}
/* Setup TEID Hash */
if (pdr->f_teid_len)
ogs_pfcp_object_teid_hash_set(OGS_PFCP_OBJ_PDR_TYPE, pdr, false);
}
/* Send Buffered Packet to gNB */
@ -374,9 +289,14 @@ void sgwu_sxa_handle_session_modification_request(
}
}
ogs_assert(OGS_OK ==
sgwu_pfcp_send_session_modification_response(
xact, sess, created_pdr, num_of_created_pdr));
if (ogs_pfcp_self()->up_function_features.ftup == 0)
ogs_assert(OGS_OK ==
sgwu_pfcp_send_session_modification_response(
xact, sess, NULL, 0));
else
ogs_assert(OGS_OK ==
sgwu_pfcp_send_session_modification_response(
xact, sess, created_pdr, num_of_created_pdr));
return;
cleanup:

View File

@ -2142,37 +2142,51 @@ void smf_sess_create_indirect_data_forwarding(smf_sess_t *sess)
pdr->f_teid.choose_id = OGS_PFCP_INDIRECT_DATA_FORWARDING_CHOOSE_ID;
pdr->f_teid_len = 2;
} else {
ogs_gtpu_resource_t *resource = NULL;
/*
* CHOOSE_ID is set in INDIRECT so that all PDRs must be set
* to the same TEID.
*
* If sess->handover.upf_dl_teid is set in the PDR of
* the first QoS flow, the PDRs of the remaining QoS flows use
* the same TEID.
*/
if (ogs_list_first(&sess->bearer_list) == qos_flow) {
ogs_gtpu_resource_t *resource = NULL;
if (sess->handover.upf_dl_addr)
ogs_freeaddrinfo(sess->handover.upf_dl_addr);
if (sess->handover.upf_dl_addr6)
ogs_freeaddrinfo(sess->handover.upf_dl_addr6);
if (sess->handover.upf_dl_addr)
ogs_freeaddrinfo(sess->handover.upf_dl_addr);
if (sess->handover.upf_dl_addr6)
ogs_freeaddrinfo(sess->handover.upf_dl_addr6);
resource = ogs_pfcp_find_gtpu_resource(
&sess->pfcp_node->gtpu_resource_list,
sess->session.name, OGS_PFCP_INTERFACE_ACCESS);
resource = ogs_pfcp_find_gtpu_resource(
&sess->pfcp_node->gtpu_resource_list,
sess->session.name, OGS_PFCP_INTERFACE_ACCESS);
if (resource) {
ogs_user_plane_ip_resource_info_to_sockaddr(&resource->info,
&sess->handover.upf_dl_addr,
&sess->handover.upf_dl_addr6);
if (resource->info.teidri)
sess->handover.upf_dl_teid =
OGS_PFCP_GTPU_INDEX_TO_TEID(
pdr->teid, resource->info.teidri,
resource->info.teid_range);
else
sess->handover.upf_dl_teid = pdr->teid;
} else {
if (sess->pfcp_node->addr.ogs_sa_family == AF_INET)
ogs_assert(OGS_OK == ogs_copyaddrinfo(
&sess->handover.upf_dl_addr,
&sess->pfcp_node->addr));
else if (sess->pfcp_node->addr.ogs_sa_family == AF_INET6)
ogs_assert(OGS_OK == ogs_copyaddrinfo(
&sess->handover.upf_dl_addr6,
&sess->pfcp_node->addr));
else
ogs_assert_if_reached();
if (resource) {
ogs_user_plane_ip_resource_info_to_sockaddr(&resource->info,
&sess->handover.upf_dl_addr, &sess->handover.upf_dl_addr6);
if (resource->info.teidri)
sess->handover.upf_dl_teid = OGS_PFCP_GTPU_INDEX_TO_TEID(
pdr->teid, resource->info.teidri,
resource->info.teid_range);
else
sess->handover.upf_dl_teid = pdr->teid;
} else {
if (sess->pfcp_node->addr.ogs_sa_family == AF_INET)
ogs_assert(OGS_OK == ogs_copyaddrinfo(
&sess->handover.upf_dl_addr, &sess->pfcp_node->addr));
else if (sess->pfcp_node->addr.ogs_sa_family == AF_INET6)
ogs_assert(OGS_OK == ogs_copyaddrinfo(
&sess->handover.upf_dl_addr6, &sess->pfcp_node->addr));
else
ogs_assert_if_reached();
sess->handover.upf_dl_teid = pdr->teid;
}
}
ogs_assert(OGS_OK ==

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2022 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -452,7 +452,7 @@ test_can_proceed:
OGS_FSM_TRAN(s, &smf_gsm_state_wait_pfcp_establishment);
ogs_assert(OGS_OK ==
smf_epc_pfcp_send_session_establishment_request(
sess, e->gtp_xact));
sess, e->gtp_xact, 0));
} else {
/* FIXME: tear down Gx/Gy session
* if its sm_data.*init_err == ER_DIAMETER_SUCCESS */
@ -671,21 +671,28 @@ void smf_gsm_state_wait_pfcp_establishment(ogs_fsm_t *s, smf_event_t *e)
send_gtp_create_err_msg(sess, e->gtp_xact, gtp_cause);
return;
}
switch (gtp_xact->gtp_version) {
case 1:
rv = smf_gtp1_send_create_pdp_context_response(sess, gtp_xact);
break;
case 2:
rv = smf_gtp2_send_create_session_response(sess, gtp_xact);
break;
default:
rv = OGS_ERROR;
break;
}
/* If no CreatePDPCtxResp can be sent, then tear down the session: */
if (rv != OGS_OK) {
OGS_FSM_TRAN(s, &smf_gsm_state_wait_pfcp_deletion);
return;
gtp_xact = pfcp_xact->assoc_xact;
if (gtp_xact) {
switch (gtp_xact->gtp_version) {
case 1:
rv = smf_gtp1_send_create_pdp_context_response(
sess, gtp_xact);
break;
case 2:
rv = smf_gtp2_send_create_session_response(
sess, gtp_xact);
break;
default:
rv = OGS_ERROR;
break;
}
/* If no CreatePDPCtxResp can be sent,
* then tear down the session: */
if (rv != OGS_OK) {
OGS_FSM_TRAN(s, &smf_gsm_state_wait_pfcp_deletion);
return;
}
}
if (sess->gtp_rat_type == OGS_GTP2_RAT_TYPE_WLAN) {
@ -739,6 +746,9 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e)
smf_sess_t *sess = NULL;
ogs_pkbuf_t *pkbuf = NULL;
ogs_pfcp_xact_t *pfcp_xact = NULL;
ogs_pfcp_message_t *pfcp_message = NULL;
ogs_nas_5gs_message_t *nas_message = NULL;
ogs_sbi_stream_t *stream = NULL;
@ -815,6 +825,38 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e)
}
break;
case SMF_EVT_N4_MESSAGE:
pfcp_xact = e->pfcp_xact;
ogs_assert(pfcp_xact);
pfcp_message = e->pfcp_message;
ogs_assert(pfcp_message);
switch (pfcp_message->h.type) {
case OGS_PFCP_SESSION_ESTABLISHMENT_RESPONSE_TYPE:
if ((pfcp_xact->create_flags &
OGS_PFCP_CREATE_RESTORATION_INDICATION)) {
ogs_pfcp_session_establishment_response_t *rsp = NULL;
ogs_pfcp_f_seid_t *up_f_seid = NULL;
rsp = &pfcp_message->pfcp_session_establishment_response;
if (rsp->up_f_seid.presence == 0) {
ogs_error("No UP F-SEID");
break;
}
up_f_seid = rsp->up_f_seid.data;
ogs_assert(up_f_seid);
sess->upf_n4_seid = be64toh(up_f_seid->seid);
} else {
ogs_error("cannot handle PFCP Session Establishment Response");
}
break;
default:
ogs_error("cannot handle PFCP message type[%d]",
pfcp_message->h.type);
}
break;
case OGS_EVENT_SBI_SERVER:
sbi_message = e->h.sbi.message;
ogs_assert(sbi_message);

View File

@ -21,7 +21,7 @@
#include "n4-build.h"
ogs_pkbuf_t *smf_n4_build_session_establishment_request(
uint8_t type, smf_sess_t *sess)
uint8_t type, smf_sess_t *sess, ogs_pfcp_xact_t *xact)
{
ogs_pfcp_message_t *pfcp_message = NULL;
ogs_pfcp_session_establishment_request_t *req = NULL;
@ -46,6 +46,7 @@ ogs_pkbuf_t *smf_n4_build_session_establishment_request(
ogs_assert(sess);
smf_ue = sess->smf_ue;
ogs_assert(smf_ue);
ogs_assert(xact);
pfcp_message = ogs_calloc(1, sizeof(*pfcp_message));
if (!pfcp_message) {
@ -159,6 +160,16 @@ ogs_pkbuf_t *smf_n4_build_session_establishment_request(
req->s_nssai.data = &sess->s_nssai;
}
/* Restoration Indication */
if (xact->create_flags & OGS_PFCP_CREATE_RESTORATION_INDICATION) {
ogs_pfcp_sereq_flags_t sereq_flags;
sereq_flags.value = 0;
sereq_flags.restoration_indication = 1;
req->pfcpsereq_flags.presence = 1;
req->pfcpsereq_flags.u8 = sereq_flags.value;
}
pfcp_message->h.type = type;
pkbuf = ogs_pfcp_build_msg(pfcp_message);
ogs_expect(pkbuf);

View File

@ -27,7 +27,7 @@ extern "C" {
#endif
ogs_pkbuf_t *smf_n4_build_session_establishment_request(
uint8_t type, smf_sess_t *sess);
uint8_t type, smf_sess_t *sess, ogs_pfcp_xact_t *xact);
ogs_pkbuf_t *smf_n4_build_pdr_to_modify_list(
uint8_t type, smf_sess_t *sess, ogs_pfcp_xact_t *xact);
ogs_pkbuf_t *smf_n4_build_qos_flow_to_modify_list(

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -148,8 +148,6 @@ uint8_t smf_5gc_n4_handle_session_establishment_response(
{
int i;
ogs_sbi_stream_t *stream = NULL;
uint8_t cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED;
uint8_t offending_ie_value = 0;
@ -164,9 +162,6 @@ uint8_t smf_5gc_n4_handle_session_establishment_response(
ogs_debug("Session Establishment Response [5gc]");
stream = xact->assoc_stream;
ogs_assert(stream);
ogs_pfcp_xact_commit(xact);
if (rsp->up_f_seid.presence == 0) {
@ -732,7 +727,6 @@ uint8_t smf_epc_n4_handle_session_establishment_response(
uint8_t cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED;
smf_bearer_t *bearer = NULL;
ogs_gtp_xact_t *gtp_xact = NULL;
ogs_pfcp_f_seid_t *up_f_seid = NULL;
@ -742,9 +736,6 @@ uint8_t smf_epc_n4_handle_session_establishment_response(
ogs_debug("Session Establishment Response [epc]");
gtp_xact = xact->assoc_xact;
ogs_assert(gtp_xact);
ogs_pfcp_xact_commit(xact);
if (rsp->up_f_seid.presence == 0) {

View File

@ -630,7 +630,7 @@ bool smf_npcf_smpolicycontrol_handle_create(
up2cp_pdr->precedence = OGS_PFCP_UP2CP_PDR_PRECEDENCE;
ogs_assert(OGS_OK ==
smf_5gc_pfcp_send_session_establishment_request(sess, stream));
smf_5gc_pfcp_send_session_establishment_request(sess, 0));
return true;

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -362,7 +362,7 @@ int smf_pfcp_send_modify_list(
}
int smf_5gc_pfcp_send_session_establishment_request(
smf_sess_t *sess, ogs_sbi_stream_t *stream)
smf_sess_t *sess, uint64_t flags)
{
int rv;
ogs_pkbuf_t *n4buf = NULL;
@ -370,7 +370,6 @@ int smf_5gc_pfcp_send_session_establishment_request(
ogs_pfcp_xact_t *xact = NULL;
ogs_assert(sess);
ogs_assert(stream);
xact = ogs_pfcp_xact_local_create(sess->pfcp_node, sess_5gc_timeout, sess);
if (!xact) {
@ -378,14 +377,44 @@ int smf_5gc_pfcp_send_session_establishment_request(
return OGS_ERROR;
}
xact->assoc_stream = stream;
xact->local_seid = sess->smf_n4_seid;
xact->create_flags = flags;
memset(&h, 0, sizeof(ogs_pfcp_header_t));
h.type = OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE;
/*
* 7.2.2.4.2 Conditions for Sending SEID=0 in PFCP Header
*
* If a peer's SEID is not available, the SEID field shall still be present
* in the header and its value shall be set to "0" in the following messages:
*
* - PFCP Session Establishment Request message on Sxa/Sxb/Sxc/N4;
*
* - If a node receives a message for which it has no session, i.e.
* if SEID in the PFCP header is not known, it shall respond
* with "Session context not found" cause in the corresponding
* response message to the sender, the SEID used in the PFCP header
* in the response message shall be then set to "0";
*
* - If a node receives a request message containing protocol error,
* e.g. Mandatory IE missing, which requires the receiver
* to reject the message as specified in clause 7.6, it shall reject
* the request message. For the response message, the node should look up
* the remote peer's SEID and accordingly set SEID in the PFCP header
* and the message cause code. As an implementation option,
* the node may not look up the remote peer's SEID and
* set the PFCP header SEID to "0" in the response message.
* However in this case, the cause value shall not be set
* to "Session not found".
*
* - When the UP function sends PFCP Session Report Request message
* over N4 towards another SMF or another PFCP entity in the SMF
* as specified in clause 5.22.2 and clause 5.22.3.
*/
h.seid = sess->upf_n4_seid;
n4buf = smf_n4_build_session_establishment_request(h.type, sess);
n4buf = smf_n4_build_session_establishment_request(h.type, sess, xact);
if (!n4buf) {
ogs_error("smf_n4_build_session_establishment_request() failed");
return OGS_ERROR;
@ -506,7 +535,7 @@ int smf_5gc_pfcp_send_session_deletion_request(
}
int smf_epc_pfcp_send_session_establishment_request(
smf_sess_t *sess, void *gtp_xact)
smf_sess_t *sess, void *gtp_xact, uint64_t flags)
{
int rv;
ogs_pkbuf_t *n4buf = NULL;
@ -524,12 +553,43 @@ int smf_epc_pfcp_send_session_establishment_request(
xact->epc = true; /* EPC PFCP transaction */
xact->assoc_xact = gtp_xact;
xact->local_seid = sess->smf_n4_seid;
xact->create_flags = flags;
memset(&h, 0, sizeof(ogs_pfcp_header_t));
h.type = OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE;
/*
* 7.2.2.4.2 Conditions for Sending SEID=0 in PFCP Header
*
* If a peer's SEID is not available, the SEID field shall still be present
* in the header and its value shall be set to "0" in the following messages:
*
* - PFCP Session Establishment Request message on Sxa/Sxb/Sxc/N4;
*
* - If a node receives a message for which it has no session, i.e.
* if SEID in the PFCP header is not known, it shall respond
* with "Session context not found" cause in the corresponding
* response message to the sender, the SEID used in the PFCP header
* in the response message shall be then set to "0";
*
* - If a node receives a request message containing protocol error,
* e.g. Mandatory IE missing, which requires the receiver
* to reject the message as specified in clause 7.6, it shall reject
* the request message. For the response message, the node should look up
* the remote peer's SEID and accordingly set SEID in the PFCP header
* and the message cause code. As an implementation option,
* the node may not look up the remote peer's SEID and
* set the PFCP header SEID to "0" in the response message.
* However in this case, the cause value shall not be set
* to "Session not found".
*
* - When the UP function sends PFCP Session Report Request message
* over N4 towards another SMF or another PFCP entity in the SMF
* as specified in clause 5.22.2 and clause 5.22.3.
*/
h.seid = sess->upf_n4_seid;
n4buf = smf_n4_build_session_establishment_request(h.type, sess);
n4buf = smf_n4_build_session_establishment_request(h.type, sess, xact);
if (!n4buf) {
ogs_error("smf_n4_build_session_establishment_request() failed");
return OGS_ERROR;

View File

@ -36,7 +36,7 @@ int smf_pfcp_send_modify_list(
ogs_pfcp_xact_t *xact, ogs_time_t duration);
int smf_5gc_pfcp_send_session_establishment_request(
smf_sess_t *sess, ogs_sbi_stream_t *stream);
smf_sess_t *sess, uint64_t flags);
int smf_5gc_pfcp_send_all_pdr_modification_request(
smf_sess_t *sess, ogs_sbi_stream_t *stream,
uint64_t flags, ogs_time_t duration);
@ -47,7 +47,7 @@ int smf_5gc_pfcp_send_session_deletion_request(
smf_sess_t *sess, ogs_sbi_stream_t *stream, int trigger);
int smf_epc_pfcp_send_session_establishment_request(
smf_sess_t *sess, void *gtp_xact);
smf_sess_t *sess, void *gtp_xact, uint64_t flags);
int smf_epc_pfcp_send_all_pdr_modification_request(
smf_sess_t *sess, void *gtp_xact, ogs_pkbuf_t *gtpbuf,
uint64_t flags, uint8_t gtp_pti, uint8_t gtp_cause);

View File

@ -22,6 +22,7 @@
#include "n4-handler.h"
static void pfcp_restoration(ogs_pfcp_node_t *node);
static void reselect_upf(ogs_pfcp_node_t *node);
static void node_timeout(ogs_pfcp_xact_t *xact, void *data);
@ -191,7 +192,7 @@ void smf_pfcp_state_associated(ogs_fsm_t *s, smf_event_t *e)
ogs_pfcp_send_heartbeat_request(node, node_timeout));
if (node->restoration_required == true) {
/* PFCP Restoration is being performed after PFCP association */
pfcp_restoration(node);
node->restoration_required = false;
ogs_error("PFCP restoration");
}
@ -244,6 +245,7 @@ void smf_pfcp_state_associated(ogs_fsm_t *s, smf_event_t *e)
* If the peer PFCP entity is performing the association,
* Restoration can be performed immediately.
*/
pfcp_restoration(node);
node->restoration_required = false;
ogs_error("PFCP restoration");
}
@ -270,6 +272,7 @@ void smf_pfcp_state_associated(ogs_fsm_t *s, smf_event_t *e)
* If the peer PFCP entity is performing the association,
* Restoration can be performed immediately.
*/
pfcp_restoration(node);
node->restoration_required = false;
ogs_error("PFCP restoration");
}
@ -409,10 +412,52 @@ void smf_pfcp_state_exception(ogs_fsm_t *s, smf_event_t *e)
}
}
static void pfcp_restoration(ogs_pfcp_node_t *node)
{
smf_ue_t *smf_ue = NULL;
char buf1[OGS_ADDRSTRLEN];
char buf2[OGS_ADDRSTRLEN];
ogs_list_for_each(&smf_self()->smf_ue_list, smf_ue) {
smf_sess_t *sess = NULL;
ogs_assert(smf_ue);
ogs_list_for_each(&smf_ue->sess_list, sess) {
ogs_assert(sess);
if (node == sess->pfcp_node) {
if (sess->epc) {
ogs_info("UE IMSI[%s] APN[%s] IPv4[%s] IPv6[%s]",
smf_ue->imsi_bcd, sess->session.name,
sess->ipv4 ?
OGS_INET_NTOP(&sess->ipv4->addr, buf1) : "",
sess->ipv6 ?
OGS_INET6_NTOP(&sess->ipv6->addr, buf2) : "");
ogs_assert(OGS_OK ==
smf_epc_pfcp_send_session_establishment_request(
sess, NULL,
OGS_PFCP_CREATE_RESTORATION_INDICATION));
} else {
ogs_info("UE SUPI[%s] DNN[%s] IPv4[%s] IPv6[%s]",
smf_ue->supi, sess->session.name,
sess->ipv4 ?
OGS_INET_NTOP(&sess->ipv4->addr, buf1) : "",
sess->ipv6 ?
OGS_INET6_NTOP(&sess->ipv6->addr, buf2) : "");
ogs_assert(OGS_OK ==
smf_5gc_pfcp_send_session_establishment_request(
sess, OGS_PFCP_CREATE_RESTORATION_INDICATION));
}
}
}
}
}
static void reselect_upf(ogs_pfcp_node_t *node)
{
int r;
smf_ue_t *smf_ue = NULL, *next_ue = NULL;;
smf_ue_t *smf_ue = NULL;
ogs_pfcp_node_t *iter = NULL;
ogs_assert(node);
@ -434,19 +479,18 @@ static void reselect_upf(ogs_pfcp_node_t *node)
return;
}
ogs_list_for_each_safe(&smf_self()->smf_ue_list, next_ue, smf_ue) {
smf_sess_t *sess = NULL, *next_sess = NULL;;
ogs_list_for_each(&smf_self()->smf_ue_list, smf_ue) {
smf_sess_t *sess = NULL;
ogs_assert(smf_ue);
ogs_list_for_each_safe(&smf_ue->sess_list, next_sess, sess) {
ogs_list_for_each(&smf_ue->sess_list, sess) {
ogs_assert(sess);
if (sess->epc) {
ogs_error("[%s:%s] EPC restoration is not implemented",
smf_ue->imsi_bcd, sess->session.name);
} else {
ogs_assert(sess->sm_context_ref);
if (node == sess->pfcp_node) {
if (node == sess->pfcp_node) {
if (sess->epc) {
ogs_error("[%s:%s] EPC restoration is not implemented",
smf_ue->imsi_bcd, sess->session.name);
} else {
smf_npcf_smpolicycontrol_param_t param;
ogs_info("[%s:%d] SMF-initiated Deletion",
@ -479,18 +523,6 @@ static void node_timeout(ogs_pfcp_xact_t *xact, void *data)
switch (type) {
case OGS_PFCP_HEARTBEAT_REQUEST_TYPE:
ogs_assert(data);
/*
* The code below is not secure.
* Session does not differentiate between EPC and 5GC.
* And, it does not check whether there are other PFCP Nodes.
*
* So, UPF redundancy will be implemented later.
*
* We plan to do this again after testing with restoration first
* in case peer PFCP restarts.
*/
reselect_upf(data);
e = smf_event_new(SMF_EVT_N4_NO_HEARTBEAT);

View File

@ -367,7 +367,10 @@ upf_sess_t *upf_sess_add_by_message(ogs_pfcp_message_t *message)
sess = upf_sess_find_by_smf_n4_f_seid(f_seid);
if (!sess) {
sess = upf_sess_add(f_seid);
if (!sess) return NULL;
if (!sess) {
ogs_error("No Session Context");
return NULL;
}
}
ogs_assert(sess);

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -425,6 +425,8 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
switch(pfcp_object->type) {
case OGS_PFCP_OBJ_PDR_TYPE:
/* UPF does not use PDR TYPE */
ogs_assert_if_reached();
pdr = (ogs_pfcp_pdr_t *)pfcp_object;
ogs_assert(pdr);
break;

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -55,6 +55,9 @@ void upf_n4_handle_session_establishment_request(
uint8_t offending_ie_value = 0;
int i;
ogs_pfcp_sereq_flags_t sereq_flags;
bool restoration_indication = false;
upf_metrics_inst_global_inc(UPF_METR_GLOB_CTR_SM_N4SESSIONESTABREQ);
ogs_assert(xact);
@ -74,9 +77,14 @@ void upf_n4_handle_session_establishment_request(
return;
}
memset(&sereq_flags, 0, sizeof(sereq_flags));
if (req->pfcpsereq_flags.presence == 1)
sereq_flags.value = req->pfcpsereq_flags.u8;
for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) {
created_pdr[i] = ogs_pfcp_handle_create_pdr(&sess->pfcp,
&req->create_pdr[i], &cause_value, &offending_ie_value);
&req->create_pdr[i], &sereq_flags,
&cause_value, &offending_ie_value);
if (created_pdr[i] == NULL)
break;
}
@ -116,6 +124,18 @@ void upf_n4_handle_session_establishment_request(
if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED)
goto cleanup;
/* PFCPSEReq-Flags */
if (sereq_flags.restoration_indication == 1) {
for (i = 0; i < num_of_created_pdr; i++) {
pdr = created_pdr[i];
ogs_assert(pdr);
if (pdr->f_teid_len)
ogs_pfcp_pdr_swap_teid(pdr);
}
restoration_indication = true;
}
/* Setup GTP Node */
ogs_list_for_each(&sess->pfcp.far_list, far) {
ogs_assert(OGS_ERROR != ogs_pfcp_setup_far_gtpu_node(far));
@ -155,65 +175,9 @@ void upf_n4_handle_session_establishment_request(
}
/* Setup UPF-N3-TEID & QFI Hash */
if (pdr->f_teid_len) {
ogs_pfcp_object_type_e type = OGS_PFCP_OBJ_SESS_TYPE;
if (ogs_pfcp_self()->up_function_features.ftup &&
pdr->f_teid.ch) {
ogs_pfcp_pdr_t *choosed_pdr = NULL;
if (pdr->f_teid.chid) {
choosed_pdr = ogs_pfcp_pdr_find_by_choose_id(
&sess->pfcp, pdr->f_teid.choose_id);
if (!choosed_pdr) {
pdr->chid = true;
pdr->choose_id = pdr->f_teid.choose_id;
}
} else {
type = OGS_PFCP_OBJ_PDR_TYPE;
}
if (choosed_pdr) {
pdr->f_teid_len = choosed_pdr->f_teid_len;
memcpy(&pdr->f_teid, &choosed_pdr->f_teid, pdr->f_teid_len);
} else {
ogs_gtpu_resource_t *resource = NULL;
resource = ogs_pfcp_find_gtpu_resource(
&ogs_gtp_self()->gtpu_resource_list,
pdr->dnn, OGS_PFCP_INTERFACE_ACCESS);
if (resource) {
ogs_assert(
(resource->info.v4 && pdr->f_teid.ipv4) ||
(resource->info.v6 && pdr->f_teid.ipv6));
ogs_assert(OGS_OK ==
ogs_pfcp_user_plane_ip_resource_info_to_f_teid(
&resource->info, &pdr->f_teid, &pdr->f_teid_len));
if (resource->info.teidri)
pdr->f_teid.teid = OGS_PFCP_GTPU_INDEX_TO_TEID(
pdr->teid, resource->info.teidri,
resource->info.teid_range);
else
pdr->f_teid.teid = pdr->teid;
} else {
ogs_assert(
(ogs_gtp_self()->gtpu_addr && pdr->f_teid.ipv4) ||
(ogs_gtp_self()->gtpu_addr6 && pdr->f_teid.ipv6));
ogs_assert(OGS_OK ==
ogs_pfcp_sockaddr_to_f_teid(
pdr->f_teid.ipv4 ?
ogs_gtp_self()->gtpu_addr : NULL,
pdr->f_teid.ipv6 ?
ogs_gtp_self()->gtpu_addr6 : NULL,
&pdr->f_teid, &pdr->f_teid_len));
pdr->f_teid.teid = pdr->teid;
}
}
}
ogs_pfcp_object_teid_hash_set(type, pdr);
}
if (pdr->f_teid_len)
ogs_pfcp_object_teid_hash_set(
OGS_PFCP_OBJ_SESS_TYPE, pdr, restoration_indication);
}
/* Send Buffered Packet to gNB/SGW */
@ -223,9 +187,16 @@ void upf_n4_handle_session_establishment_request(
}
}
ogs_assert(OGS_OK ==
upf_pfcp_send_session_establishment_response(
xact, sess, created_pdr, num_of_created_pdr));
if (restoration_indication == true ||
ogs_pfcp_self()->up_function_features.ftup == 0)
ogs_assert(OGS_OK ==
upf_pfcp_send_session_establishment_response(
xact, sess, NULL, 0));
else
ogs_assert(OGS_OK ==
upf_pfcp_send_session_establishment_response(
xact, sess, created_pdr, num_of_created_pdr));
return;
cleanup:
@ -266,7 +237,7 @@ void upf_n4_handle_session_modification_request(
for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) {
created_pdr[i] = ogs_pfcp_handle_create_pdr(&sess->pfcp,
&req->create_pdr[i], &cause_value, &offending_ie_value);
&req->create_pdr[i], NULL, &cause_value, &offending_ie_value);
if (created_pdr[i] == NULL)
break;
}
@ -399,70 +370,13 @@ void upf_n4_handle_session_modification_request(
ogs_pfcp_far_f_teid_hash_set(far);
}
/* Setup UPF-N3-TEID & QFI Hash */
for (i = 0; i < num_of_created_pdr; i++) {
pdr = created_pdr[i];
ogs_assert(pdr);
if (pdr->f_teid_len) {
ogs_pfcp_object_type_e type = OGS_PFCP_OBJ_SESS_TYPE;
if (ogs_pfcp_self()->up_function_features.ftup &&
pdr->f_teid.ch) {
ogs_pfcp_pdr_t *choosed_pdr = NULL;
if (pdr->f_teid.chid) {
choosed_pdr = ogs_pfcp_pdr_find_by_choose_id(
&sess->pfcp, pdr->f_teid.choose_id);
if (!choosed_pdr) {
pdr->chid = true;
pdr->choose_id = pdr->f_teid.choose_id;
}
} else {
type = OGS_PFCP_OBJ_PDR_TYPE;
}
if (choosed_pdr) {
pdr->f_teid_len = choosed_pdr->f_teid_len;
memcpy(&pdr->f_teid, &choosed_pdr->f_teid, pdr->f_teid_len);
} else {
ogs_gtpu_resource_t *resource = NULL;
resource = ogs_pfcp_find_gtpu_resource(
&ogs_gtp_self()->gtpu_resource_list,
pdr->dnn, OGS_PFCP_INTERFACE_ACCESS);
if (resource) {
ogs_assert(
(resource->info.v4 && pdr->f_teid.ipv4) ||
(resource->info.v6 && pdr->f_teid.ipv6));
ogs_assert(OGS_OK ==
ogs_pfcp_user_plane_ip_resource_info_to_f_teid(
&resource->info, &pdr->f_teid, &pdr->f_teid_len));
if (resource->info.teidri)
pdr->f_teid.teid = OGS_PFCP_GTPU_INDEX_TO_TEID(
pdr->teid, resource->info.teidri,
resource->info.teid_range);
else
pdr->f_teid.teid = pdr->teid;
} else {
ogs_assert(
(ogs_gtp_self()->gtpu_addr && pdr->f_teid.ipv4) ||
(ogs_gtp_self()->gtpu_addr6 && pdr->f_teid.ipv6));
ogs_assert(OGS_OK ==
ogs_pfcp_sockaddr_to_f_teid(
pdr->f_teid.ipv4 ?
ogs_gtp_self()->gtpu_addr : NULL,
pdr->f_teid.ipv6 ?
ogs_gtp_self()->gtpu_addr6 : NULL,
&pdr->f_teid, &pdr->f_teid_len));
pdr->f_teid.teid = pdr->teid;
}
}
}
ogs_pfcp_object_teid_hash_set(type, pdr);
}
/* Setup UPF-N3-TEID & QFI Hash */
if (pdr->f_teid_len)
ogs_pfcp_object_teid_hash_set(OGS_PFCP_OBJ_SESS_TYPE, pdr, false);
}
/* Send Buffered Packet to gNB/SGW */
@ -472,9 +386,14 @@ void upf_n4_handle_session_modification_request(
}
}
ogs_assert(OGS_OK ==
upf_pfcp_send_session_modification_response(
xact, sess, created_pdr, num_of_created_pdr));
if (ogs_pfcp_self()->up_function_features.ftup == 0)
ogs_assert(OGS_OK ==
upf_pfcp_send_session_modification_response(
xact, sess, NULL, 0));
else
ogs_assert(OGS_OK ==
upf_pfcp_send_session_modification_response(
xact, sess, created_pdr, num_of_created_pdr));
return;
cleanup:

View File

@ -208,7 +208,6 @@ int upf_pfcp_send_session_modification_response(
ogs_pfcp_header_t h;
ogs_assert(xact);
ogs_assert(created_pdr);
memset(&h, 0, sizeof(ogs_pfcp_header_t));
h.type = OGS_PFCP_SESSION_MODIFICATION_RESPONSE_TYPE;

View File

@ -281,12 +281,9 @@ void upf_pfcp_state_associated(ogs_fsm_t *s, upf_event_t *e)
&message->pfcp_association_setup_response);
break;
case OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE:
if (message->h.seid_presence && message->h.seid == 0) {
ogs_expect(!sess);
sess = upf_sess_add_by_message(message);
if (sess)
OGS_SETUP_PFCP_NODE(sess, node);
}
sess = upf_sess_add_by_message(message);
if (sess)
OGS_SETUP_PFCP_NODE(sess, node);
upf_n4_handle_session_establishment_request(
sess, xact, &message->pfcp_session_establishment_request);
break;