[#203] Rollback based on the spec

If the new Create Session Request received by the SGW/PGW collides with
an existing active PDN connection context, the PGW/SGW should delete it.
This commit is contained in:
Sukchan Lee 2019-11-05 22:32:32 +09:00
parent c131295dfb
commit 6f44ff5f4d
4 changed files with 122 additions and 6 deletions

View File

@ -79,6 +79,8 @@ void pgw_context_init(void)
ogs_pool_init(&pgw_pf_pool, ogs_config()->pool.pf);
self.sess_hash = ogs_hash_make();
ogs_list_init(&self.sess_list);
context_initiaized = 1;
@ -93,6 +95,9 @@ void pgw_context_final(void)
pgw_dev_remove_all();
pgw_subnet_remove_all();
ogs_assert(self.sess_hash);
ogs_hash_destroy(self.sess_hash);
ogs_pool_final(&pgw_bearer_pool);
ogs_pool_final(&pgw_sess_pool);
ogs_pool_final(&pgw_pf_pool);
@ -707,6 +712,16 @@ int pgw_context_parse_config(void)
return OGS_OK;
}
static void *sess_hash_keygen(uint8_t *out, int *out_len,
uint8_t *imsi, int imsi_len, char *apn)
{
memcpy(out, imsi, imsi_len);
ogs_cpystrn((char*)(out+imsi_len), apn, OGS_MAX_APN_LEN+1);
*out_len = imsi_len+strlen((char*)(out+imsi_len));
return out;
}
pgw_sess_t *pgw_sess_add(
uint8_t *imsi, int imsi_len, char *apn,
uint8_t pdn_type, uint8_t ebi)
@ -779,6 +794,11 @@ pgw_sess_t *pgw_sess_add(
sess->ipv4 ? INET_NTOP(&sess->ipv4->addr, buf1) : "",
sess->ipv6 ? INET6_NTOP(&sess->ipv6->addr, buf2) : "");
/* Generate Hash Key : IMSI + APN */
sess_hash_keygen(sess->hash_keybuf, &sess->hash_keylen,
imsi, imsi_len, apn);
ogs_hash_set(self.sess_hash, sess->hash_keybuf, sess->hash_keylen, sess);
ogs_list_add(&self.sess_list, sess);
stats_add_session();
@ -792,6 +812,8 @@ int pgw_sess_remove(pgw_sess_t *sess)
ogs_list_remove(&self.sess_list, sess);
ogs_hash_set(self.sess_hash, sess->hash_keybuf, sess->hash_keylen, NULL);
if (sess->ipv4)
pgw_ue_ip_free(sess->ipv4);
if (sess->ipv6)
@ -825,6 +847,18 @@ pgw_sess_t *pgw_sess_find_by_teid(uint32_t teid)
return pgw_sess_find(teid);
}
pgw_sess_t *pgw_sess_find_by_imsi_apn(
uint8_t *imsi, int imsi_len, char *apn)
{
uint8_t keybuf[OGS_MAX_IMSI_LEN+OGS_MAX_APN_LEN+1];
int keylen = 0;
ogs_assert(self.sess_hash);
sess_hash_keygen(keybuf, &keylen, imsi, imsi_len, apn);
return (pgw_sess_t *)ogs_hash_get(self.sess_hash, keybuf, keylen);
}
ogs_gtp_node_t *pgw_sgw_add_by_message(ogs_gtp_message_t *message)
{
int rv;
@ -890,10 +924,31 @@ pgw_sess_t *pgw_sess_add_by_message(ogs_gtp_message_t *message)
apn, req->pdn_type.u8,
req->bearer_contexts_to_be_created.eps_bearer_id.u8);
sess = pgw_sess_add(req->imsi.data, req->imsi.len, apn,
req->pdn_type.u8,
req->bearer_contexts_to_be_created.eps_bearer_id.u8);
ogs_assert(sess);
/*
* 3GPP TS 29.274 Release 15, Page 38
*
* If the new Create Session Request received by the PGW collides with
* an existing PDN connection context (the existing PDN connection context
* is identified with the triplet [IMSI, EPS Bearer ID, Interface type],
* where applicable Interface type here is S2a TWAN GTP-C interface or
* S2b ePDG GTP-C interface or S5/S8 SGW GTP-C interface, and where IMSI
* shall be replaced by TAC and SNR part of ME Identity for emergency
* attached UE without UICC or authenticated IMSI), this Create Session
* Request shall be treated as a request for a new session. Before creating
* the new session, the PGW should delete:
*
* - the existing PDN connection context, if the Create Session Request
* collides with the default bearer of an existing PDN connection context;
* - the existing dedicated bearer context, if the Create Session Request
* collides with a dedicated bearer of an existing PDN connection context.
*/
sess = pgw_sess_find_by_imsi_apn(req->imsi.data, req->imsi.len, apn);
if (!sess) {
sess = pgw_sess_add(req->imsi.data, req->imsi.len, apn,
req->pdn_type.u8,
req->bearer_contexts_to_be_created.eps_bearer_id.u8);
ogs_assert(sess);
}
return sess;
}

View File

@ -87,6 +87,8 @@ typedef struct pgw_context_s {
ogs_list_t sgw_s5u_list; /* SGW GTPU Node List */
ogs_list_t ip_pool_list;
ogs_hash_t *sess_hash; /* hash table (IMSI+APN) */
ogs_list_t sess_list;
} pgw_context_t;
@ -146,6 +148,9 @@ typedef struct pgw_sess_s {
ogs_tai_t tai;
ogs_e_cgi_t e_cgi;
uint8_t hash_keybuf[OGS_MAX_IMSI_LEN+OGS_MAX_APN_LEN+1];
int hash_keylen;
ogs_list_t bearer_list;
/* Related Context */
@ -229,6 +234,7 @@ int pgw_sess_remove(pgw_sess_t *sess);
void pgw_sess_remove_all(void);
pgw_sess_t *pgw_sess_find(uint32_t index);
pgw_sess_t *pgw_sess_find_by_teid(uint32_t teid);
pgw_sess_t *pgw_sess_find_by_imsi_apn(uint8_t *imsi, int imsi_len, char *apn);
pgw_bearer_t *pgw_bearer_add(pgw_sess_t *sess);
int pgw_bearer_remove(pgw_bearer_t *bearer);

View File

@ -57,6 +57,8 @@ void sgw_context_init(void)
ogs_pool_init(&sgw_bearer_pool, ogs_config()->pool.bearer);
ogs_pool_init(&sgw_tunnel_pool, ogs_config()->pool.tunnel);
self.imsi_ue_hash = ogs_hash_make();
ogs_list_init(&self.sgw_ue_list);
context_initialized = 1;
@ -68,6 +70,9 @@ void sgw_context_final(void)
sgw_ue_remove_all();
ogs_assert(self.imsi_ue_hash);
ogs_hash_destroy(self.imsi_ue_hash);
ogs_pool_final(&sgw_tunnel_pool);
ogs_pool_final(&sgw_bearer_pool);
ogs_pool_final(&sgw_sess_pool);
@ -435,8 +440,31 @@ sgw_ue_t *sgw_ue_add_by_message(ogs_gtp_message_t *message)
ogs_trace("sgw_ue_add_by_message() - IMSI ");
ogs_log_hexdump(OGS_LOG_TRACE, req->imsi.data, req->imsi.len);
sgw_ue = sgw_ue_add(req->imsi.data, req->imsi.len);
ogs_assert(sgw_ue);
/*
* 3GPP TS 29.274 Release 15, Page 38
*
* If the new Create Session Request received by the SGW collides with
* an existing active PDN connection context (the existing PDN connection
* context is identified with the tuple [IMSI, EPS Bearer ID], where IMSI
* shall be replaced by TAC and SNR part of ME Identity for emergency
* attached UE without UICC or authenticated IMSI), this Create Session
* Request shall be treated as a request for a new session. Before creating
* the new session, the SGW should delete:
*
* - the existing PDN connection context locally, if the Create Session
* Request is received with the TEID set to zero in the header, or
* if it is received with a TEID not set to zero in the header and
* it collides with the default bearer of an existing PDN connection
* context;
* - the existing dedicated bearer context locally, if the Create Session
* Request collides with an existing dedicated bearer context and
* the message is received with a TEID not set to zero in the header.
*/
sgw_ue = sgw_ue_find_by_imsi(req->imsi.data, req->imsi.len);
if (!sgw_ue) {
sgw_ue = sgw_ue_add(req->imsi.data, req->imsi.len);
ogs_assert(sgw_ue);
}
return sgw_ue;
}
@ -463,6 +491,8 @@ sgw_ue_t *sgw_ue_add(uint8_t *imsi, int imsi_len)
ogs_list_init(&sgw_ue->sess_list);
ogs_hash_set(self.imsi_ue_hash, sgw_ue->imsi, sgw_ue->imsi_len, sgw_ue);
ogs_list_add(&self.sgw_ue_list, sgw_ue);
return sgw_ue;
@ -474,6 +504,8 @@ int sgw_ue_remove(sgw_ue_t *sgw_ue)
ogs_list_remove(&self.sgw_ue_list, sgw_ue);
ogs_hash_set(self.imsi_ue_hash, sgw_ue->imsi, sgw_ue->imsi_len, NULL);
sgw_sess_remove_all(sgw_ue);
ogs_pool_free(&sgw_ue_pool, sgw_ue);
@ -489,6 +521,25 @@ void sgw_ue_remove_all(void)
sgw_ue_remove(sgw_ue);
}
sgw_ue_t *sgw_ue_find_by_imsi_bcd(char *imsi_bcd)
{
uint8_t imsi[OGS_MAX_IMSI_LEN];
int imsi_len = 0;
ogs_assert(imsi_bcd);
ogs_bcd_to_buffer(imsi_bcd, imsi, &imsi_len);
return sgw_ue_find_by_imsi(imsi, imsi_len);
}
sgw_ue_t *sgw_ue_find_by_imsi(uint8_t *imsi, int imsi_len)
{
ogs_assert(imsi && imsi_len);
return (sgw_ue_t *)ogs_hash_get(self.imsi_ue_hash, imsi, imsi_len);
}
sgw_ue_t *sgw_ue_find_by_teid(uint32_t teid)
{
return ogs_pool_find(&sgw_ue_pool, teid);

View File

@ -61,6 +61,8 @@ typedef struct sgw_context_s {
ogs_list_t enb_s1u_list; /* eNB GTPU Node List */
ogs_list_t pgw_s5u_list; /* PGW GTPU Node List */
ogs_hash_t *imsi_ue_hash; /* hash table (IMSI : SGW_UE) */
ogs_list_t sgw_ue_list; /* SGW_UE List */
} sgw_context_t;
@ -153,6 +155,8 @@ int sgw_context_parse_config(void);
ogs_gtp_node_t *sgw_mme_add_by_message(ogs_gtp_message_t *message);
sgw_ue_t *sgw_ue_add_by_message(ogs_gtp_message_t *message);
sgw_ue_t *sgw_ue_find_by_imsi(uint8_t *imsi, int imsi_len);
sgw_ue_t *sgw_ue_find_by_imsi_bcd(char *imsi_bcd);
sgw_ue_t *sgw_ue_find_by_teid(uint32_t teid);
sgw_ue_t *sgw_ue_add(uint8_t *imsi, int imsi_len);