5GC UPF selection is added

This commit is contained in:
Sukchan Lee 2020-07-19 21:42:58 -04:00
parent 9b3176ca4a
commit 661da4e034
27 changed files with 841 additions and 508 deletions

View File

@ -9,19 +9,21 @@ parameter:
mme:
freeDiameter: @sysconfdir@/freeDiameter/mme.conf
s1ap:
addr: 127.0.0.1
gtpc:
addr: 127.0.0.1
sgsap:
gummei:
plmn_id:
mcc: 001
mnc: 01
mcc: 901
mnc: 70
mme_gid: 2
mme_code: 1
tai:
plmn_id:
mcc: 001
mnc: 01
tac: 12345
mcc: 901
mnc: 70
tac: 1
security:
integrity_order : [ EIA1, EIA2, EIA0 ]
@ -36,6 +38,7 @@ sgw:
gtpc:
addr: 127.0.0.2
gtpu:
addr: 127.0.0.2
pgw:
freeDiameter: @sysconfdir@/freeDiameter/pgw.conf

View File

@ -204,18 +204,20 @@ logger:
mme:
freeDiameter: @sysconfdir@/freeDiameter/mme.conf
s1ap:
addr: 127.0.0.1
gtpc:
addr: 127.0.0.1
gummei:
plmn_id:
mcc: 001
mnc: 01
mcc: 901
mnc: 70
mme_gid: 2
mme_code: 1
tai:
plmn_id:
mcc: 001
mnc: 01
tac: 12345
mcc: 901
mnc: 70
tac: 1
security:
integrity_order : [ EIA1, EIA2, EIA0 ]
ciphering_order : [ EEA0, EEA1, EEA2 ]

View File

@ -60,6 +60,7 @@ sgw:
gtpc:
addr: 127.0.0.2
gtpu:
addr: 127.0.0.2
#
# parameter:

View File

@ -139,3 +139,29 @@ int ogs_gtp_ip_to_f_teid(ogs_ip_t *ip, ogs_gtp_f_teid_t *f_teid, int *len)
return OGS_OK;
}
int ogs_gtp_paa_to_ip(ogs_paa_t *paa, ogs_ip_t *ip)
{
ogs_assert(paa);
ogs_assert(ip);
memset(ip, 0, sizeof *ip);
if (paa->pdn_type == OGS_GTP_PDN_TYPE_IPV4V6) {
ip->ipv4 = 1;
ip->addr = paa->both.addr;
ip->ipv6 = 1;
memcpy(ip->addr6, paa->both.addr6, OGS_IPV6_LEN);
} else if (paa->pdn_type == OGS_GTP_PDN_TYPE_IPV4) {
ip->ipv4 = 1;
ip->ipv6 = 0;
ip->addr = paa->addr;
} else if (paa->pdn_type == OGS_GTP_PDN_TYPE_IPV6) {
ip->ipv4 = 0;
ip->ipv6 = 1;
memcpy(ip->addr6, paa->addr6, OGS_IPV6_LEN);
} else
ogs_assert_if_reached();
return OGS_OK;
}

View File

@ -35,6 +35,8 @@ int ogs_gtp_sockaddr_to_f_teid(ogs_sockaddr_t *addr, ogs_sockaddr_t *addr6,
int ogs_gtp_f_teid_to_ip(ogs_gtp_f_teid_t *f_teid, ogs_ip_t *ip);
int ogs_gtp_ip_to_f_teid(ogs_ip_t *ip, ogs_gtp_f_teid_t *f_teid, int *len);
int ogs_gtp_paa_to_ip(ogs_paa_t *paa, ogs_ip_t *ip);
#ifdef __cplusplus
}
#endif

View File

@ -868,9 +868,36 @@ ogs_pfcp_pdr_t *ogs_pfcp_pdr_find(
return NULL;
}
ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_by_teid(uint32_t teid)
static uint64_t pdr_hash_keygen(uint32_t teid, uint8_t qfi)
{
return (ogs_pfcp_pdr_t *)ogs_hash_get(self.pdr_hash, &teid, sizeof(teid));
uint64_t hashkey = (teid << 8) + qfi;
return hashkey;
}
void ogs_pfcp_pdr_hash_set(ogs_pfcp_pdr_t *pdr)
{
ogs_pfcp_qer_t *qer = NULL;
uint8_t qfi = 0;
ogs_assert(pdr);
qer = pdr->qer;
if (qer && qer->qfi) qfi = qer->qfi;
if (pdr->hashkey)
ogs_hash_set(ogs_pfcp_self()->pdr_hash, &pdr->hashkey,
sizeof(pdr->hashkey), NULL);
pdr->hashkey = pdr_hash_keygen(pdr->f_teid.teid, qfi);
ogs_hash_set(ogs_pfcp_self()->pdr_hash, &pdr->hashkey,
sizeof(pdr->hashkey), pdr);
}
ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_by_teid_and_qfi(uint32_t teid, uint8_t qfi)
{
uint64_t hashkey = pdr_hash_keygen(teid, qfi);
return (ogs_pfcp_pdr_t *)ogs_hash_get(self.pdr_hash,
&hashkey, sizeof(hashkey));
}
ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_or_add(
@ -911,7 +938,6 @@ void ogs_pfcp_pdr_associate_far(ogs_pfcp_pdr_t *pdr, ogs_pfcp_far_t *far)
ogs_assert(far);
pdr->far = far;
far->pdr = pdr;
}
void ogs_pfcp_pdr_associate_urr(ogs_pfcp_pdr_t *pdr, ogs_pfcp_urr_t *urr)
{
@ -919,7 +945,6 @@ void ogs_pfcp_pdr_associate_urr(ogs_pfcp_pdr_t *pdr, ogs_pfcp_urr_t *urr)
ogs_assert(urr);
pdr->urr = urr;
urr->pdr = pdr;
}
void ogs_pfcp_pdr_associate_qer(ogs_pfcp_pdr_t *pdr, ogs_pfcp_qer_t *qer)
{
@ -927,7 +952,6 @@ void ogs_pfcp_pdr_associate_qer(ogs_pfcp_pdr_t *pdr, ogs_pfcp_qer_t *qer)
ogs_assert(qer);
pdr->qer = qer;
qer->pdr = pdr;
}
void ogs_pfcp_pdr_remove(ogs_pfcp_pdr_t *pdr)
@ -937,9 +961,9 @@ void ogs_pfcp_pdr_remove(ogs_pfcp_pdr_t *pdr)
ogs_list_remove(&pdr->sess->pdr_list, pdr);
if (pdr->f_teid.teid)
ogs_hash_set(self.pdr_hash, &pdr->f_teid.teid,
sizeof(pdr->f_teid.teid), NULL);
if (pdr->hashkey)
ogs_hash_set(ogs_pfcp_self()->pdr_hash, &pdr->hashkey,
sizeof(pdr->hashkey), NULL);
ogs_pool_free(&ogs_pfcp_pdr_pool, pdr);
}

View File

@ -115,11 +115,17 @@ typedef struct ogs_pfcp_sess_s {
typedef struct ogs_pfcp_pdr_s {
ogs_lnode_t lnode;
uint64_t hashkey;
ogs_pfcp_pdr_id_t id;
ogs_pfcp_precedence_t precedence;
ogs_pfcp_interface_t src_if;
ogs_pfcp_ue_ip_addr_t ue_ip_addr;
int ue_ip_addr_len;
ogs_pfcp_f_teid_t f_teid;
int f_teid_len;
ogs_pfcp_outer_header_removal_t outer_header_removal;
ogs_pfcp_far_t *far;
@ -149,7 +155,6 @@ typedef struct ogs_pfcp_far_s {
/* Related Context */
ogs_pfcp_sess_t *sess;
void *gnode;
ogs_pfcp_pdr_t *pdr;
} ogs_pfcp_far_t;
typedef struct ogs_pfcp_urr_s {
@ -157,7 +162,6 @@ typedef struct ogs_pfcp_urr_s {
ogs_pfcp_urr_id_t id;
ogs_pfcp_pdr_t *pdr;
ogs_pfcp_sess_t *sess;
} ogs_pfcp_urr_t;
@ -172,7 +176,6 @@ typedef struct ogs_pfcp_qer_s {
uint8_t qfi;
ogs_pfcp_pdr_t *pdr;
ogs_pfcp_sess_t *sess;
} ogs_pfcp_qer_t;
@ -256,9 +259,11 @@ ogs_pfcp_pdr_t *ogs_pfcp_sess_default_pdr(ogs_pfcp_sess_t *sess);
void ogs_pfcp_sess_clear(ogs_pfcp_sess_t *sess);
ogs_pfcp_pdr_t *ogs_pfcp_pdr_add(ogs_pfcp_sess_t *sess);
void ogs_pfcp_pdr_hash_set(ogs_pfcp_pdr_t *pdr);
ogs_pfcp_pdr_t *ogs_pfcp_pdr_find(
ogs_pfcp_sess_t *sess, ogs_pfcp_pdr_id_t id);
ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_by_teid(uint32_t teid);
ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_by_teid_and_qfi(uint32_t teid, uint8_t qfi);
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_reorder_by_precedence(

View File

@ -644,25 +644,38 @@ static ogs_pfcp_node_t *selected_upf_node(
return next ? next : ogs_list_first(&ogs_pfcp_self()->n4_list);
}
smf_sess_t *smf_sess_add_by_apn(smf_ue_t *smf_ue, char *apn,
uint8_t pdn_type, uint8_t ebi, ogs_paa_t *paa, ogs_gtp_uli_t *uli)
void smf_sess_select_upf(smf_sess_t *sess)
{
char buf[OGS_ADDRSTRLEN];
ogs_assert(sess);
/*
* When used for the first time, if last node is set,
* the search is performed from the first SGW in a round-robin manner.
*/
if (ogs_pfcp_self()->node == NULL)
ogs_pfcp_self()->node = ogs_list_last(&ogs_pfcp_self()->n4_list);
/* setup GTP session with selected UPF */
ogs_pfcp_self()->node = selected_upf_node(ogs_pfcp_self()->node, sess);
ogs_assert(ogs_pfcp_self()->node);
OGS_SETUP_PFCP_NODE(sess, ogs_pfcp_self()->node);
ogs_debug("UE using UPF on IP[%s]",
OGS_ADDR(&ogs_pfcp_self()->node->addr, buf));
/* iterate to next UPF in list for next UE attach */
ogs_pfcp_self()->node = ogs_list_next(ogs_pfcp_self()->node);
}
smf_sess_t *smf_sess_add_by_apn(smf_ue_t *smf_ue, char *apn)
{
ogs_debug("smf_sess_add_by_apn");
smf_event_t e;
char buf[OGS_ADDRSTRLEN];
char buf1[OGS_ADDRSTRLEN];
char buf2[OGS_ADDRSTRLEN];
smf_sess_t *sess = NULL;
smf_bearer_t *bearer = NULL;
ogs_pfcp_pdr_t *pdr = NULL;
ogs_pfcp_subnet_t *subnet6 = NULL;
ogs_assert(smf_ue);
ogs_assert(apn);
ogs_assert(paa);
ogs_assert(uli);
ogs_pool_alloc(&smf_sess_pool, &sess);
if (!sess) {
@ -682,83 +695,6 @@ smf_sess_t *smf_sess_add_by_apn(smf_ue_t *smf_ue, char *apn,
/* Set APN */
ogs_cpystrn(sess->pdn.apn, apn, OGS_MAX_APN_LEN+1);
/* UE IP Address */
sess->pdn.paa.pdn_type = pdn_type;
ogs_expect(pdn_type == paa->pdn_type);
if (pdn_type == OGS_GTP_PDN_TYPE_IPV4) {
sess->ipv4 = ogs_pfcp_ue_ip_alloc(
AF_INET, apn, (uint8_t *)&(paa->addr));
ogs_assert(sess->ipv4);
sess->pdn.paa.addr = sess->ipv4->addr[0];
ogs_hash_set(self.ipv4_hash, sess->ipv4->addr, OGS_IPV4_LEN, sess);
} else if (pdn_type == OGS_GTP_PDN_TYPE_IPV6) {
sess->ipv6 = ogs_pfcp_ue_ip_alloc(
AF_INET6, apn, (paa->addr6));
ogs_assert(sess->ipv6);
subnet6 = sess->ipv6->subnet;
ogs_assert(subnet6);
sess->pdn.paa.len = subnet6->prefixlen;
memcpy(sess->pdn.paa.addr6, sess->ipv6->addr, OGS_IPV6_LEN);
ogs_hash_set(self.ipv6_hash, sess->ipv6->addr, OGS_IPV6_LEN, sess);
} else if (pdn_type == OGS_GTP_PDN_TYPE_IPV4V6) {
sess->ipv4 = ogs_pfcp_ue_ip_alloc(
AF_INET, apn, (uint8_t *)&(paa->both.addr));
ogs_assert(sess->ipv4);
sess->ipv6 = ogs_pfcp_ue_ip_alloc(
AF_INET6, apn, (paa->both.addr6));
ogs_assert(sess->ipv6);
subnet6 = sess->ipv6->subnet;
ogs_assert(subnet6);
sess->pdn.paa.both.addr = sess->ipv4->addr[0];
sess->pdn.paa.both.len = subnet6->prefixlen;
memcpy(sess->pdn.paa.both.addr6, sess->ipv6->addr, OGS_IPV6_LEN);
ogs_hash_set(self.ipv4_hash, sess->ipv4->addr, OGS_IPV4_LEN, sess);
ogs_hash_set(self.ipv6_hash, sess->ipv6->addr, OGS_IPV6_LEN, sess);
} else
ogs_assert_if_reached();
memcpy(&sess->e_tai, &uli->tai, sizeof(sess->e_tai));
memcpy(&sess->e_cgi, &uli->e_cgi, sizeof(sess->e_cgi));
ogs_info("UE IMSI:[%s] APN:[%s] IPv4:[%s] IPv6:[%s]",
sess->imsi_bcd, apn,
sess->ipv4 ? OGS_INET_NTOP(&sess->ipv4->addr, buf1) : "",
sess->ipv6 ? OGS_INET6_NTOP(&sess->ipv6->addr, buf2) : "");
/*
* When used for the first time, if last node is set,
* the search is performed from the first SGW in a round-robin manner.
*/
if (ogs_pfcp_self()->node == NULL)
ogs_pfcp_self()->node = ogs_list_last(&ogs_pfcp_self()->n4_list);
/* setup GTP session with selected UPF */
ogs_pfcp_self()->node = selected_upf_node(ogs_pfcp_self()->node, sess);
ogs_assert(ogs_pfcp_self()->node);
OGS_SETUP_PFCP_NODE(sess, ogs_pfcp_self()->node);
ogs_debug("UE using UPF on IP[%s]",
OGS_ADDR(&ogs_pfcp_self()->node->addr, buf));
/* iterate to next UPF in list for next UE attach */
ogs_pfcp_self()->node = ogs_list_next(ogs_pfcp_self()->node);
/* Set Default Bearer */
ogs_list_init(&sess->bearer_list);
bearer = smf_bearer_add(sess);
ogs_assert(bearer);
bearer->ebi = ebi; /* EPC only */
/* Default PDRs is set to lowest precedence(highest precedence value). */
ogs_list_for_each(&bearer->pfcp.pdr_list, pdr)
pdr->precedence = 0xffffffff;
/* Setup SBI */
sess->sbi.client_wait.timer = ogs_timer_add(
self.timer_mgr, smf_timer_sbi_client_wait_expire, sess);
@ -779,9 +715,7 @@ smf_sess_t *smf_sess_add_by_gtp_message(ogs_gtp_message_t *message)
{
smf_ue_t *smf_ue = NULL;
smf_sess_t *sess = NULL;
ogs_paa_t *paa = NULL;
char apn[OGS_MAX_APN_LEN];
ogs_gtp_uli_t uli;
ogs_gtp_create_session_request_t *req = &message->create_session_request;
@ -793,39 +727,11 @@ smf_sess_t *smf_sess_add_by_gtp_message(ogs_gtp_message_t *message)
ogs_error("No APN");
return NULL;
}
if (req->bearer_contexts_to_be_created.presence == 0) {
ogs_error("No Bearer");
return NULL;
}
if (req->bearer_contexts_to_be_created.eps_bearer_id.presence == 0) {
ogs_error("No EPS Bearer ID");
return NULL;
}
if (req->pdn_type.presence == 0) {
ogs_error("No PDN Type");
return NULL;
}
if (req->pdn_address_allocation.presence == 0) {
ogs_error("No PAA");
return NULL;
}
if (req->user_location_information.presence == 0) {
ogs_error("No UE Location Information");
return NULL;
}
ogs_fqdn_parse(apn,
req->access_point_name.data, req->access_point_name.len);
ogs_trace("smf_sess_add_by_message() [APN:%s, PDN:%d, EDI:%d]",
apn, req->pdn_type.u8,
req->bearer_contexts_to_be_created.eps_bearer_id.u8);
paa = (ogs_paa_t *)req->pdn_address_allocation.data;
ogs_gtp_parse_uli(&uli, &req->user_location_information);
ogs_trace("smf_sess_add_by_message() [APN:%s]", apn);
/*
* 7.2.1 in 3GPP TS 29.274 Release 15
@ -859,20 +765,15 @@ smf_sess_t *smf_sess_add_by_gtp_message(ogs_gtp_message_t *message)
smf_sess_remove(sess);
}
sess = smf_sess_add_by_apn(smf_ue, apn, req->pdn_type.u8,
req->bearer_contexts_to_be_created.eps_bearer_id.u8, paa, &uli);
sess = smf_sess_add_by_apn(smf_ue, apn);
return sess;
}
smf_sess_t *smf_sess_add_by_psi(smf_ue_t *smf_ue, uint8_t psi)
{
ogs_debug("smf_sess_add_by_psi");
smf_event_t e;
smf_sess_t *sess = NULL;
smf_bearer_t *bearer = NULL;
ogs_pfcp_pdr_t *pdr = NULL;
ogs_assert(smf_ue);
ogs_assert(psi != OGS_NAS_PDU_SESSION_IDENTITY_UNASSIGNED);
@ -905,33 +806,6 @@ smf_sess_t *smf_sess_add_by_psi(smf_ue_t *smf_ue, uint8_t psi)
sess->smf_n4_teid = sess->index;
sess->smf_n4_seid = sess->index;
/* Select UPF with round-robin manner */
if (ogs_pfcp_self()->node == NULL)
ogs_pfcp_self()->node = ogs_list_first(&ogs_pfcp_self()->n4_list);
for (; ogs_pfcp_self()->node;
ogs_pfcp_self()->node = ogs_list_next(ogs_pfcp_self()->node)) {
if (OGS_FSM_CHECK(
&ogs_pfcp_self()->node->sm, smf_pfcp_state_associated)) {
OGS_SETUP_PFCP_NODE(sess, ogs_pfcp_self()->node);
break;
}
}
/* Set Default Bearer */
ogs_list_init(&sess->bearer_list);
bearer = smf_bearer_add(sess);
ogs_assert(bearer);
/* QFI is only used in 5GC */
bearer->qfi = OGS_NEXT_ID(
sess->qos_flow_identifier, 1, OGS_MAX_QOS_FLOW_ID+1);
/* Default PDRs is set to lowest precedence(highest precedence value). */
ogs_list_for_each(&bearer->pfcp.pdr_list, pdr)
pdr->precedence = 0xffffffff;
/* Setup SBI */
sess->sbi.client_wait.timer = ogs_timer_add(
self.timer_mgr, smf_timer_sbi_client_wait_expire, sess);
@ -988,6 +862,70 @@ smf_sess_t *smf_sess_add_by_sbi_message(ogs_sbi_message_t *message)
return sess;
}
void smf_sess_set_ue_ip(smf_sess_t *sess)
{
ogs_pfcp_subnet_t *subnet6 = NULL;
smf_ue_t *smf_ue = NULL;
ogs_assert(sess);
smf_ue = sess->smf_ue;
ogs_assert(smf_ue);
sess->pdn.paa.pdn_type = sess->pdn.pdn_type;
ogs_assert(sess->pdn.pdn_type);
if (sess->ipv4) {
ogs_hash_set(smf_self()->ipv4_hash,
sess->ipv4->addr, OGS_IPV4_LEN, NULL);
ogs_pfcp_ue_ip_free(sess->ipv4);
}
if (sess->ipv6) {
ogs_hash_set(smf_self()->ipv6_hash,
sess->ipv6->addr, OGS_IPV6_LEN, NULL);
ogs_pfcp_ue_ip_free(sess->ipv6);
}
if (sess->pdn.pdn_type == OGS_PDU_SESSION_TYPE_IPV4) {
sess->ipv4 = ogs_pfcp_ue_ip_alloc(
AF_INET, sess->pdn.apn, (uint8_t *)&sess->pdn.ue_ip.addr);
ogs_assert(sess->ipv4);
sess->pdn.paa.addr = sess->ipv4->addr[0];
ogs_hash_set(smf_self()->ipv4_hash,
sess->ipv4->addr, OGS_IPV4_LEN, sess);
} else if (sess->pdn.pdn_type == OGS_PDU_SESSION_TYPE_IPV6) {
sess->ipv6 = ogs_pfcp_ue_ip_alloc(
AF_INET6, sess->pdn.apn, sess->pdn.ue_ip.addr6);
ogs_assert(sess->ipv6);
subnet6 = sess->ipv6->subnet;
ogs_assert(subnet6);
sess->pdn.paa.len = subnet6->prefixlen;
memcpy(sess->pdn.paa.addr6, sess->ipv6->addr, OGS_IPV6_LEN);
ogs_hash_set(smf_self()->ipv6_hash,
sess->ipv6->addr, OGS_IPV6_LEN, sess);
} else if (sess->pdn.pdn_type == OGS_PDU_SESSION_TYPE_IPV4V6) {
sess->ipv4 = ogs_pfcp_ue_ip_alloc(
AF_INET, sess->pdn.apn, (uint8_t *)&sess->pdn.ue_ip.addr);
ogs_assert(sess->ipv4);
sess->ipv6 = ogs_pfcp_ue_ip_alloc(
AF_INET6, sess->pdn.apn, sess->pdn.ue_ip.addr6);
ogs_assert(sess->ipv6);
subnet6 = sess->ipv6->subnet;
ogs_assert(subnet6);
sess->pdn.paa.both.addr = sess->ipv4->addr[0];
sess->pdn.paa.both.len = subnet6->prefixlen;
memcpy(sess->pdn.paa.both.addr6, sess->ipv6->addr, OGS_IPV6_LEN);
ogs_hash_set(smf_self()->ipv4_hash,
sess->ipv4->addr, OGS_IPV4_LEN, sess);
ogs_hash_set(smf_self()->ipv6_hash,
sess->ipv6->addr, OGS_IPV6_LEN, sess);
} else
ogs_assert_if_reached();
}
void smf_sess_remove(smf_sess_t *sess)
{
int i;
@ -1035,6 +973,11 @@ void smf_sess_remove(smf_sess_t *sess)
if (sess->dnn)
ogs_free(sess->dnn);
if (sess->upf_n3_addr)
ogs_freeaddrinfo(sess->upf_n3_addr);
if (sess->upf_n3_addr6)
ogs_freeaddrinfo(sess->upf_n3_addr6);
/* Free SBI object memory */
ogs_sbi_object_free(&sess->sbi);
ogs_timer_delete(sess->sbi.client_wait.timer);
@ -1119,6 +1062,80 @@ smf_sess_t *smf_sess_find_by_ipv6(uint32_t *addr6)
return (smf_sess_t *)ogs_hash_get(self.ipv6_hash, addr6, OGS_IPV6_LEN);
}
smf_bearer_t *smf_qos_flow_add(smf_sess_t *sess)
{
smf_bearer_t *qos_flow = NULL;
ogs_pfcp_pdr_t *dl_pdr = NULL;
ogs_pfcp_pdr_t *ul_pdr = NULL;
ogs_pfcp_far_t *dl_far = NULL;
ogs_pfcp_far_t *ul_far = NULL;
ogs_pfcp_qer_t *qer = NULL;
ogs_assert(sess);
ogs_pool_alloc(&smf_bearer_pool, &qos_flow);
ogs_assert(qos_flow);
memset(qos_flow, 0, sizeof *qos_flow);
qos_flow->index = ogs_pool_index(&smf_bearer_pool, qos_flow);
ogs_assert(qos_flow->index > 0 && qos_flow->index <=
ogs_config()->pool.bearer);
ogs_list_init(&qos_flow->pf_list);
dl_pdr = ogs_pfcp_pdr_add(&qos_flow->pfcp);
ogs_assert(dl_pdr);
dl_pdr->id = OGS_NEXT_ID(sess->pdr_id, 1, OGS_MAX_NUM_OF_PDR+1);
dl_pdr->src_if = OGS_PFCP_INTERFACE_CORE;
ul_pdr = ogs_pfcp_pdr_add(&qos_flow->pfcp);
ogs_assert(ul_pdr);
ul_pdr->id = OGS_NEXT_ID(sess->pdr_id, 1, OGS_MAX_NUM_OF_PDR+1);
ul_pdr->src_if = OGS_PFCP_INTERFACE_ACCESS;
dl_far = ogs_pfcp_far_add(&qos_flow->pfcp);
ogs_assert(dl_far);
dl_far->id = OGS_NEXT_ID(sess->far_id, 1, OGS_MAX_NUM_OF_FAR+1);
dl_far->dst_if = OGS_PFCP_INTERFACE_ACCESS;
ogs_pfcp_pdr_associate_far(dl_pdr, dl_far);
ul_far = ogs_pfcp_far_add(&qos_flow->pfcp);
ogs_assert(ul_far);
ul_far->id = OGS_NEXT_ID(sess->far_id, 1, OGS_MAX_NUM_OF_FAR+1);
ul_far->dst_if = OGS_PFCP_INTERFACE_CORE;
ogs_pfcp_pdr_associate_far(ul_pdr, ul_far);
qer = ogs_pfcp_qer_add(&qos_flow->pfcp);
ogs_assert(qer);
qer->id = OGS_NEXT_ID(sess->qer_id, 1, OGS_MAX_NUM_OF_QER+1);
ogs_pfcp_pdr_associate_qer(dl_pdr, qer);
ogs_pfcp_pdr_associate_qer(ul_pdr, qer);
/* Allocate QFI */
qer->qfi = OGS_NEXT_ID(sess->qos_flow_identifier, 1, OGS_MAX_QOS_FLOW_ID+1);
qos_flow->qfi = qer->qfi;
qos_flow->sess = sess;
ogs_list_add(&sess->bearer_list, qos_flow);
return qos_flow;
}
smf_bearer_t *smf_qos_flow_find_by_qfi(smf_sess_t *sess, uint8_t qfi)
{
smf_bearer_t *qos_flow = NULL;
ogs_assert(sess);
ogs_list_for_each(&sess->bearer_list, qos_flow) {
if (qos_flow->qfi == qfi)
return qos_flow;
}
return qos_flow;
}
smf_bearer_t *smf_bearer_add(smf_sess_t *sess)
{
smf_bearer_t *bearer = NULL;
@ -1169,26 +1186,30 @@ smf_bearer_t *smf_bearer_add(smf_sess_t *sess)
sess->pdn.apn, OGS_PFCP_INTERFACE_ACCESS);
if (resource) {
ogs_pfcp_user_plane_ip_resource_info_to_sockaddr(&resource->info,
&bearer->upf_addr, &bearer->upf_addr6);
ogs_assert(bearer->upf_addr || bearer->upf_addr6);
&bearer->upf_s5u_addr, &bearer->upf_s5u_addr6);
ogs_assert(bearer->upf_s5u_addr || bearer->upf_s5u_addr6);
if (resource->info.teidri)
bearer->upf_n3_teid = UPF_S5U_INDEX_TO_TEID(
bearer->upf_s5u_teid = UPF_GTPU_INDEX_TO_TEID(
bearer->index, resource->info.teidri,
resource->info.teid_range);
else
bearer->upf_n3_teid = bearer->index;
bearer->upf_s5u_teid = bearer->index;
} else {
if (sess->pfcp_node->addr.ogs_sa_family == AF_INET)
ogs_copyaddrinfo(&bearer->upf_addr, &sess->pfcp_node->addr);
ogs_copyaddrinfo(&bearer->upf_s5u_addr, &sess->pfcp_node->addr);
else if (sess->pfcp_node->addr.ogs_sa_family == AF_INET6)
ogs_copyaddrinfo(&bearer->upf_addr6, &sess->pfcp_node->addr);
ogs_copyaddrinfo(&bearer->upf_s5u_addr6, &sess->pfcp_node->addr);
else
ogs_assert_if_reached();
ogs_assert(bearer->upf_addr || bearer->upf_addr6);
ogs_assert(bearer->upf_s5u_addr || bearer->upf_s5u_addr6);
bearer->upf_n3_teid = bearer->index;
bearer->upf_s5u_teid = bearer->index;
}
ogs_pfcp_sockaddr_to_f_teid(bearer->upf_s5u_addr, bearer->upf_s5u_addr6,
&ul_pdr->f_teid, &ul_pdr->f_teid_len);
ul_pdr->f_teid.teid = bearer->upf_s5u_teid;
bearer->sess = sess;
ogs_list_add(&sess->bearer_list, bearer);
@ -1206,10 +1227,10 @@ int smf_bearer_remove(smf_bearer_t *bearer)
if (bearer->name)
ogs_free(bearer->name);
if (bearer->upf_addr)
ogs_freeaddrinfo(bearer->upf_addr);
if (bearer->upf_addr6)
ogs_freeaddrinfo(bearer->upf_addr6);
if (bearer->upf_s5u_addr)
ogs_freeaddrinfo(bearer->upf_s5u_addr);
if (bearer->upf_s5u_addr6)
ogs_freeaddrinfo(bearer->upf_s5u_addr6);
smf_pf_remove_all(bearer);
@ -1327,7 +1348,7 @@ bool smf_bearer_is_default(smf_bearer_t *bearer)
default_bearer = smf_default_bearer_in_sess(sess);
ogs_assert(default_bearer);
return bearer->ebi == default_bearer->ebi;
return bearer == default_bearer;
}
smf_bearer_t *smf_bearer_first(smf_sess_t *sess)
@ -1566,4 +1587,3 @@ int smf_pco_build(uint8_t *pco_buf, uint8_t *buffer, int length)
size = ogs_pco_build(pco_buf, OGS_MAX_PCO_LEN, &smf);
return size;
}

View File

@ -143,7 +143,6 @@ typedef struct smf_sess_s {
ogs_fsm_t sm; /* A state machine */
uint32_t smf_n4_teid; /* SMF-N4-TEID is derived from INDEX */
#define SMF_5GC_SESS(__sESS) ((__sESS)->sgw_s5c_teid == 0)
uint32_t sgw_s5c_teid; /* SGW-S5C-TEID is received from SGW */
#define SMF_SEID_TO_INDEX(__iNDEX) (__iNDEX & ~0x8000000000000000)
@ -152,6 +151,21 @@ typedef struct smf_sess_s {
uint64_t smf_n4_seid; /* SMF SEID is dervied from INDEX */
uint64_t upf_n4_seid; /* UPF SEID is received from Peer */
/*
* UPF-GTPU-TEID = INDEX | TEID_RANGE
* INDEX = UPF-GTPU-TEID & ~TEID_RANGE
*/
#define UPF_GTPU_TEID_TO_INDEX(__tEID, __iND, __rANGE) \
(__tEID & ~(__rANGE << (32 - __iND)))
#define UPF_GTPU_INDEX_TO_TEID(__iNDEX, __iND, __rANGE) \
(__iNDEX | (__rANGE << (32 - __iND)))
uint32_t upf_n3_teid; /* UPF-N3 TEID */
ogs_sockaddr_t *upf_n3_addr; /* UPF-N3 IPv4 */
ogs_sockaddr_t *upf_n3_addr6; /* UPF-N3 IPv6 */
uint32_t gnb_n3_teid; /* gNB-N3 TEID */
ogs_ip_t gnb_n3_ip; /* gNB-N3 IPv4/IPv6 */
char *gx_sid; /* Gx Session ID */
ogs_pfcp_pdr_id_t pdr_id; /* ID Generator(1~OGS_MAX_NUM_OF_PDR) */
@ -162,11 +176,6 @@ typedef struct smf_sess_s {
uint8_t qos_flow_identifier; /* ID Generator(1~OGS_MAX_QOS_FLOW_ID) */
/* IMSI */
uint8_t imsi[OGS_MAX_IMSI_LEN];
int imsi_len;
char imsi_bcd[OGS_MAX_IMSI_BCD_LEN+1];
char *sm_context_ref; /* smContextRef */
uint8_t psi; /* PDU session identity */
uint8_t pti; /* Procedure transaction identity */
@ -227,6 +236,11 @@ typedef struct smf_sess_s {
bool remove;
} pfcp_5gc_modify;
struct {
bool create_session_response_apn_ambr;
bool create_session_response_bearer_qos;
} gtp_5gc;;
/* UE session context is activated or not */
OpenAPI_up_cnx_state_e ueUpCnxState;
/* SMF session context is activated or not */
@ -250,20 +264,12 @@ typedef struct smf_bearer_s {
uint8_t qfi; /* 5GC */
uint8_t ebi; /* EPC */
/*
* UPF-S5U-TEID = INDEX | TEID_RANGE
* INDEX = UPF-S5U-TEID & ~TEID_RANGE
*/
#define UPF_S5U_TEID_TO_INDEX(__tEID, __iND, __rANGE) \
(__tEID & ~(__rANGE << (32 - __iND)))
#define UPF_S5U_INDEX_TO_TEID(__iNDEX, __iND, __rANGE) \
(__iNDEX | (__rANGE << (32 - __iND)))
uint32_t upf_n3_teid; /* UPF_N3 TEID */
ogs_sockaddr_t *upf_addr; /* UPF_N3 IPv4 */
ogs_sockaddr_t *upf_addr6; /* UPF_N3 IPv6 */
uint32_t upf_s5u_teid; /* UPF-S5U TEID */
ogs_sockaddr_t *upf_s5u_addr; /* UPF-S5U IPv4 */
ogs_sockaddr_t *upf_s5u_addr6; /* UPF-S5U IPv6 */
uint32_t gnb_n3_teid; /* gNB_N3 TEID */
ogs_ip_t gnb_n3_ip; /* gNB_N3 IP */
uint32_t sgw_s5u_teid; /* SGW-S5U TEID */
ogs_ip_t sgw_s5u_ip; /* SGW-S5U IPv4/IPv6 */
char *name; /* PCC Rule Name */
ogs_qos_t qos; /* QoS Infomration */
@ -308,12 +314,14 @@ smf_ue_t *smf_ue_find_by_supi(char *supi);
smf_ue_t *smf_ue_find_by_imsi(uint8_t *imsi, int imsi_len);
smf_sess_t *smf_sess_add_by_gtp_message(ogs_gtp_message_t *message);
smf_sess_t *smf_sess_add_by_apn(smf_ue_t *smf_ue, char *apn,
uint8_t pdn_type, uint8_t ebi, ogs_paa_t *paa, ogs_gtp_uli_t *uli);
smf_sess_t *smf_sess_add_by_apn(smf_ue_t *smf_ue, char *apn);
smf_sess_t *smf_sess_add_by_sbi_message(ogs_sbi_message_t *message);
smf_sess_t *smf_sess_add_by_psi(smf_ue_t *smf_ue, uint8_t psi);
void smf_sess_select_upf(smf_sess_t *sess);
void smf_sess_set_ue_ip(smf_sess_t *sess);
void smf_sess_remove(smf_sess_t *sess);
void smf_sess_remove_all(smf_ue_t *smf_ue);
@ -326,6 +334,9 @@ smf_sess_t *smf_sess_find_by_sm_context_ref(char *sm_context_ref);
smf_sess_t *smf_sess_find_by_ipv4(uint32_t addr);
smf_sess_t *smf_sess_find_by_ipv6(uint32_t *addr6);
smf_bearer_t *smf_qos_flow_add(smf_sess_t *sess);
smf_bearer_t *smf_qos_flow_find_by_qfi(smf_sess_t *sess, uint8_t qfi);
smf_bearer_t *smf_bearer_add(smf_sess_t *sess);
int smf_bearer_remove(smf_bearer_t *bearer);
void smf_bearer_remove_all(smf_sess_t *sess);

View File

@ -73,6 +73,7 @@ void smf_gx_send_ccr(smf_sess_t *sess, ogs_gtp_xact_t *xact,
uint32_t cc_request_type)
{
int ret;
smf_ue_t *smf_ue = NULL;
struct msg *req = NULL;
struct avp *avp;
@ -85,6 +86,8 @@ void smf_gx_send_ccr(smf_sess_t *sess, ogs_gtp_xact_t *xact,
ogs_assert(sess);
ogs_assert(sess->ipv4 || sess->ipv6);
smf_ue = sess->smf_ue;
ogs_assert(smf_ue);
ogs_debug("[Credit-Control-Request]");
@ -221,8 +224,8 @@ void smf_gx_send_ccr(smf_sess_t *sess, ogs_gtp_xact_t *xact,
ret = fd_msg_avp_new(ogs_diam_gx_subscription_id_data, 0, &avpch1);
ogs_assert(ret == 0);
val.os.data = (uint8_t *)sess->imsi_bcd;
val.os.len = strlen(sess->imsi_bcd);
val.os.data = (uint8_t *)smf_ue->imsi_bcd;
val.os.len = strlen(smf_ue->imsi_bcd);
ret = fd_msg_avp_setvalue (avpch1, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1);
@ -352,7 +355,8 @@ void smf_gx_send_ccr(smf_sess_t *sess, ogs_gtp_xact_t *xact,
ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(ogs_diam_gx_allocation_retention_priority, 0, &avpch1);
ret = fd_msg_avp_new(
ogs_diam_gx_allocation_retention_priority, 0, &avpch1);
ogs_assert(ret == 0);
ret = fd_msg_avp_new(ogs_diam_gx_priority_level, 0, &avpch2);
@ -615,14 +619,16 @@ static void smf_gx_cca_cb(void *data, struct msg **msg)
ret = fd_msg_search_avp(*msg, ogs_diam_gx_qos_information, &avp);
ogs_assert(ret == 0);
if (avp) {
ret = fd_avp_search_avp(avp, ogs_diam_gx_apn_aggregate_max_bitrate_ul, &avpch1);
ret = fd_avp_search_avp(
avp, ogs_diam_gx_apn_aggregate_max_bitrate_ul, &avpch1);
ogs_assert(ret == 0);
if (avpch1) {
ret = fd_msg_avp_hdr(avpch1, &hdr);
ogs_assert(ret == 0);
gx_message->pdn.ambr.uplink = hdr->avp_value->u32;
}
ret = fd_avp_search_avp(avp, ogs_diam_gx_apn_aggregate_max_bitrate_dl, &avpch1);
ret = fd_avp_search_avp(
avp, ogs_diam_gx_apn_aggregate_max_bitrate_dl, &avpch1);
ogs_assert(ret == 0);
if (avpch1) {
ret = fd_msg_avp_hdr(avpch1, &hdr);
@ -642,10 +648,12 @@ static void smf_gx_cca_cb(void *data, struct msg **msg)
gx_message->pdn.qos.qci = hdr->avp_value->u32;
}
ret = fd_avp_search_avp(avp, ogs_diam_gx_allocation_retention_priority, &avpch1);
ret = fd_avp_search_avp(
avp, ogs_diam_gx_allocation_retention_priority, &avpch1);
ogs_assert(ret == 0);
if (avpch1) {
ret = fd_avp_search_avp(avpch1, ogs_diam_gx_priority_level, &avpch2);
ret = fd_avp_search_avp(
avpch1, ogs_diam_gx_priority_level, &avpch2);
ogs_assert(ret == 0);
if (avpch2) {
ret = fd_msg_avp_hdr(avpch2, &hdr);
@ -653,7 +661,8 @@ static void smf_gx_cca_cb(void *data, struct msg **msg)
gx_message->pdn.qos.arp.priority_level = hdr->avp_value->u32;
}
ret = fd_avp_search_avp(avpch1, ogs_diam_gx_pre_emption_capability, &avpch2);
ret = fd_avp_search_avp(
avpch1, ogs_diam_gx_pre_emption_capability, &avpch2);
ogs_assert(ret == 0);
if (avpch2) {
ret = fd_msg_avp_hdr(avpch2, &hdr);
@ -791,7 +800,8 @@ out:
ogs_debug(" CC-Request-Type[%d] Number[%d] in Session Data",
sess_data->cc_request_type, sess_data->cc_request_number);
ogs_debug(" Current CC-Request-Number[%d]", cc_request_number);
if (sess_data->cc_request_type == OGS_DIAM_GX_CC_REQUEST_TYPE_TERMINATION_REQUEST &&
if (sess_data->cc_request_type ==
OGS_DIAM_GX_CC_REQUEST_TYPE_TERMINATION_REQUEST &&
sess_data->cc_request_number <= cc_request_number) {
ogs_debug(" [LAST] state_cleanup(): [%s]", sess_data->gx_sid);
state_cleanup(sess_data, NULL, NULL);

View File

@ -87,18 +87,44 @@ ogs_pkbuf_t *gsm_build_pdu_session_establishment_accept(smf_sess_t *sess)
selected_pdu_session_type->type = sess->pdn.ssc_mode;
selected_pdu_session_type->value = sess->pdn.pdn_type;
/* Default QoS Rule */
/*
* TS23.501
* 5.7.1.3 QoS Rules
*
* A default QoS rule is required to be sent to the UE for every PDU
* Session establishment and it is associated with a QoS Flow. For IP type
* PDU Session or Ethernet type PDU Session, the default QoS rule is
* the only QoS rule of a PDU Session which may contain a Packet Filter
* Set that allows all UL packets, and in this case, the highest
* precedence value shall be used for the QoS rule.
*
* As long as the default QoS rule does not contain a Packet Filter Set or
* contains a Packet Filter Set that allows all UL packets, Reflective QoS
* should not be applied for the QoS Flow which the default QoS rule is
* associated with and the RQA should not be sent for this QoS Flow.
*/
memset(qos_rule, 0, sizeof(qos_rule));
qos_rule[0].identifier = 1;
qos_rule[0].length = 6;
qos_rule[0].code = OGS_NAS_QOS_CODE_CREATE_NEW_QOS_RULE;
qos_rule[0].DQR_bit = 1;
qos_rule[0].num_of_packet_filter = 1;
qos_rule[0].pf[0].direction = OGS_NAS_QOS_DIRECTION_UPLINK;
qos_rule[0].pf[0].pf_identifier = 1;
qos_rule[0].pf[0].length = 1;
qos_rule[0].pf[0].num_of_component = 1;
qos_rule[0].pf[0].component[0].type = OGS_PACKET_FILTER_MATCH_ALL;
/*
* TS23.501
* 5.7.1.9 Precedence Value
*
* The QoS rule precedence value and the PDR precedence value determine
* the order in which a QoS rule or a PDR, respectively, shall be evaluated.
* The evaluation of the QoS rules or PDRs is performed in increasing order
* of their precedence value.
*/
qos_rule[0].precedence = 255; /* lowest precedence */
qos_rule[0].flow.segregation = 0;
qos_rule[0].flow.identifier = bearer->qfi;

View File

@ -261,8 +261,7 @@ void smf_gsm_state_released(ogs_fsm_t *s, smf_event_t *e)
break;
default:
ogs_error("[%s] Unknown event %s",
sess->imsi_bcd, smf_event_get_name(e));
ogs_error("Unknown event %s", smf_event_get_name(e));
break;
}
}
@ -286,8 +285,7 @@ void smf_gsm_state_exception(ogs_fsm_t *s, smf_event_t *e)
break;
default:
ogs_error("[%s] Unknown event %s",
sess->imsi_bcd, smf_event_get_name(e));
ogs_error("Unknown event %s", smf_event_get_name(e));
break;
}
}

View File

@ -46,6 +46,12 @@ void smf_gx_handle_cca_initial_request(
ogs_gtp_xact_t *gtp_xact)
{
int i;
smf_bearer_t *bearer = NULL;
ogs_pfcp_pdr_t *pdr = NULL;
ogs_pfcp_far_t *far = NULL;
ogs_pfcp_qer_t *qer = NULL;
ogs_assert(sess);
ogs_assert(gx_message);
ogs_assert(gtp_xact);
@ -63,12 +69,55 @@ void smf_gx_handle_cca_initial_request(
return;
}
if (sess->pdn.ambr.downlink || sess->pdn.ambr.uplink) {
smf_bearer_t *bearer = smf_default_bearer_in_sess(sess);
ogs_pfcp_pdr_t *pdr = NULL;
ogs_pfcp_qer_t *qer = NULL;
ogs_assert(bearer);
sess->num_of_pcc_rule = gx_message->num_of_pcc_rule;
for (i = 0; i < gx_message->num_of_pcc_rule; i++)
OGS_STORE_PCC_RULE(&sess->pcc_rule[i], &gx_message->pcc_rule[i]);
/* APN-AMBR
* if PCRF changes APN-AMBR, this should be included. */
sess->gtp_5gc.create_session_response_apn_ambr = false;
if ((gx_message->pdn.ambr.uplink &&
(sess->pdn.ambr.uplink / 1000) !=
(gx_message->pdn.ambr.uplink / 1000)) ||
(gx_message->pdn.ambr.downlink &&
(sess->pdn.ambr.downlink / 1000) !=
(gx_message->pdn.ambr.downlink / 1000))) {
sess->pdn.ambr.downlink = gx_message->pdn.ambr.downlink;
sess->pdn.ambr.uplink = gx_message->pdn.ambr.uplink;
sess->gtp_5gc.create_session_response_apn_ambr = true;
}
/* Bearer QoS
* if PCRF changes Bearer QoS, this should be included. */
sess->gtp_5gc.create_session_response_bearer_qos = false;
if ((gx_message->pdn.qos.qci &&
sess->pdn.qos.qci != gx_message->pdn.qos.qci) ||
(gx_message->pdn.qos.arp.priority_level &&
sess->pdn.qos.arp.priority_level !=
gx_message->pdn.qos.arp.priority_level) ||
sess->pdn.qos.arp.pre_emption_capability !=
gx_message->pdn.qos.arp.pre_emption_capability ||
sess->pdn.qos.arp.pre_emption_vulnerability !=
gx_message->pdn.qos.arp.pre_emption_vulnerability) {
sess->pdn.qos.qci = gx_message->pdn.qos.qci;
sess->pdn.qos.arp.priority_level =
gx_message->pdn.qos.arp.priority_level;
sess->pdn.qos.arp.pre_emption_capability =
gx_message->pdn.qos.arp.pre_emption_capability;
sess->pdn.qos.arp.pre_emption_vulnerability =
gx_message->pdn.qos.arp.pre_emption_vulnerability;
sess->gtp_5gc.create_session_response_bearer_qos = true;
}
bearer = smf_default_bearer_in_sess(sess);
ogs_assert(bearer);
/* Setup QER */
if (sess->pdn.ambr.downlink || sess->pdn.ambr.uplink) {
/* Only 1 QER is used per bearer */
qer = ogs_list_first(&bearer->pfcp.qer_list);
if (!qer) {
@ -79,14 +128,35 @@ void smf_gx_handle_cca_initial_request(
qer->mbr.uplink = sess->pdn.ambr.uplink;
qer->mbr.downlink = sess->pdn.ambr.downlink;
ogs_list_for_each(&bearer->pfcp.pdr_list, pdr)
ogs_pfcp_pdr_associate_qer(pdr, qer);
}
sess->num_of_pcc_rule = gx_message->num_of_pcc_rule;
for (i = 0; i < gx_message->num_of_pcc_rule; i++)
OGS_STORE_PCC_RULE(&sess->pcc_rule[i], &gx_message->pcc_rule[i]);
/* Setup FAR */
ogs_list_for_each(&bearer->pfcp.far_list, far) {
/* Set Outer Header Creation to the Default DL FAR */
if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) {
ogs_pfcp_ip_to_outer_header_creation(&bearer->sgw_s5u_ip,
&far->outer_header_creation, &far->outer_header_creation_len);
far->outer_header_creation.teid = bearer->sgw_s5u_teid;
}
}
/* Setup PDR */
ogs_list_for_each(&bearer->pfcp.pdr_list, pdr) {
/* Set UE IP Address to the Default DL PDR */
if (pdr->src_if == OGS_PFCP_INTERFACE_CORE) {
ogs_pfcp_paa_to_ue_ip_addr(&sess->pdn.paa,
&pdr->ue_ip_addr, &pdr->ue_ip_addr_len);
pdr->ue_ip_addr.sd = OGS_PFCP_UE_IP_DST;
}
/* Default PDRs is set to lowest precedence(highest precedence value) */
pdr->precedence = 0xffffffff;
if (qer)
ogs_pfcp_pdr_associate_qer(pdr, qer);
}
smf_epc_pfcp_send_session_establishment_request(sess, gtp_xact);
}

View File

@ -87,7 +87,6 @@ ogs_pkbuf_t *smf_n4_build_association_setup_response(uint8_t type,
}
static struct {
ogs_pfcp_ue_ip_addr_t addr;
ogs_pfcp_outer_header_removal_t outer_header_removal;
ogs_pfcp_f_teid_t f_teid;
char dnn[OGS_MAX_DNN_LEN];
@ -164,25 +163,21 @@ static void build_create_pdr(
}
if (pdr->src_if == OGS_PFCP_INTERFACE_CORE) { /* Downlink */
if (smf_bearer_is_default(bearer)) { /* Default Bearer */
ogs_pfcp_paa_to_ue_ip_addr(&sess->pdn.paa,
&pdrbuf[i].addr, &len);
pdrbuf[i].addr.sd = OGS_PFCP_UE_IP_DST;
if (pdr->ue_ip_addr_len) {
message->pdi.ue_ip_address.presence = 1;
message->pdi.ue_ip_address.data = &pdrbuf[i].addr;
message->pdi.ue_ip_address.len = len;
message->pdi.ue_ip_address.data = &pdr->ue_ip_addr;
message->pdi.ue_ip_address.len = pdr->ue_ip_addr_len;
}
} else if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS) { /* Uplink */
ogs_pfcp_sockaddr_to_f_teid(
bearer->upf_addr, bearer->upf_addr6,
&pdrbuf[i].f_teid, &len);
pdrbuf[i].f_teid.teid = htobe32(bearer->upf_n3_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->pdi.local_f_teid.presence = 1;
message->pdi.local_f_teid.data = &pdrbuf[i].f_teid;
message->pdi.local_f_teid.len = len;
message->pdi.local_f_teid.presence = 1;
message->pdi.local_f_teid.data = &pdrbuf[i].f_teid;
message->pdi.local_f_teid.len = pdr->f_teid_len;
}
if (sess->pdn.paa.pdn_type == OGS_GTP_PDN_TYPE_IPV4) {
pdrbuf[i].outer_header_removal.description =
@ -226,15 +221,11 @@ static void build_create_far(
ogs_pfcp_tlv_create_far_t *message, int i, ogs_pfcp_far_t *far)
{
ogs_pfcp_sess_t *pfcp_sess = NULL;
smf_bearer_t *bearer = NULL;
int len;
ogs_assert(message);
ogs_assert(far);
pfcp_sess = far->sess;
ogs_assert(pfcp_sess);
bearer = SMF_BEARER(pfcp_sess);
ogs_assert(bearer);
message->presence = 1;
message->far_id.presence = 1;
@ -249,16 +240,17 @@ static void build_create_far(
far->dst_if;
if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) { /* Downlink */
if (bearer->gnb_n3_ip.ipv4 || bearer->gnb_n3_ip.ipv6) {
ogs_pfcp_ip_to_outer_header_creation(&bearer->gnb_n3_ip,
&farbuf[i].outer_header_creation, &len);
if (far->outer_header_creation_len) {
memcpy(&farbuf[i].outer_header_creation,
&far->outer_header_creation, far->outer_header_creation_len);
farbuf[i].outer_header_creation.teid =
htobe32(bearer->gnb_n3_teid);
htobe32(far->outer_header_creation.teid);
message->forwarding_parameters.outer_header_creation.presence = 1;
message->forwarding_parameters.outer_header_creation.data =
&farbuf[i].outer_header_creation;
message->forwarding_parameters.outer_header_creation.len = len;
message->forwarding_parameters.outer_header_creation.len =
far->outer_header_creation_len;
}
}
}
@ -339,19 +331,14 @@ static void build_update_far(smf_sess_t *sess,
ogs_pfcp_tlv_update_far_t *message, int i, ogs_pfcp_far_t *far)
{
ogs_pfcp_sess_t *pfcp_sess = NULL;
smf_bearer_t *bearer = NULL;
int len;
ogs_assert(message);
ogs_assert(far);
pfcp_sess = far->sess;
ogs_assert(pfcp_sess);
bearer = SMF_BEARER(pfcp_sess);
ogs_assert(bearer);
ogs_assert(sess);
ogs_assert(far->dst_if == OGS_PFCP_INTERFACE_ACCESS);
ogs_assert(bearer->gnb_n3_ip.ipv4 || bearer->gnb_n3_ip.ipv6);
ogs_assert(far->outer_header_creation_len);
message->presence = 1;
message->far_id.presence = 1;
@ -359,10 +346,10 @@ static void build_update_far(smf_sess_t *sess,
if (sess->ueUpCnxState == OpenAPI_up_cnx_state_ACTIVATED) {
if (sess->pfcp_5gc_modify.outer_header_creation_update) {
ogs_pfcp_ip_to_outer_header_creation(&bearer->gnb_n3_ip,
&farbuf[i].outer_header_creation, &len);
memcpy(&farbuf[i].outer_header_creation,
&far->outer_header_creation, far->outer_header_creation_len);
farbuf[i].outer_header_creation.teid =
htobe32(bearer->gnb_n3_teid);
htobe32(far->outer_header_creation.teid);
message->update_forwarding_parameters.presence = 1;
message->update_forwarding_parameters.
@ -370,7 +357,7 @@ static void build_update_far(smf_sess_t *sess,
message->update_forwarding_parameters.
outer_header_creation.data = &farbuf[i].outer_header_creation;
message->update_forwarding_parameters.
outer_header_creation.len = len;
outer_header_creation.len = far->outer_header_creation_len;
}
if (far->apply_action != OGS_PFCP_APPLY_ACTION_FORW) {

View File

@ -22,7 +22,7 @@
ogs_pkbuf_t *ngap_build_pdu_session_resource_setup_request_transfer(
smf_sess_t *sess)
{
smf_bearer_t *bearer = NULL;
smf_bearer_t *qos_flow = NULL;
ogs_ip_t upf_n3_ip;
NGAP_PDUSessionResourceSetupRequestTransfer_t message;
@ -41,8 +41,8 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_setup_request_transfer(
NGAP_AllocationAndRetentionPriority_t *allocationAndRetentionPriority;
ogs_assert(sess);
bearer = smf_default_bearer_in_sess(sess);
ogs_assert(bearer);
qos_flow = smf_default_bearer_in_sess(sess);
ogs_assert(qos_flow);
ogs_debug("PDUSessionResourceSetupRequestTransfer");
memset(&message, 0, sizeof(NGAP_PDUSessionResourceSetupRequestTransfer_t));
@ -79,9 +79,9 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_setup_request_transfer(
NGAP_UPTransportLayerInformation_PR_gTPTunnel;
UPTransportLayerInformation->choice.gTPTunnel = gTPTunnel;
ogs_sockaddr_to_ip(bearer->upf_addr, bearer->upf_addr6, &upf_n3_ip);
ogs_sockaddr_to_ip(sess->upf_n3_addr, sess->upf_n3_addr6, &upf_n3_ip);
ogs_asn_ip_to_BIT_STRING(&upf_n3_ip, &gTPTunnel->transportLayerAddress);
ogs_asn_uint32_to_OCTET_STRING(bearer->upf_n3_teid, &gTPTunnel->gTP_TEID);
ogs_asn_uint32_to_OCTET_STRING(sess->upf_n3_teid, &gTPTunnel->gTP_TEID);
ie = CALLOC(1, sizeof(NGAP_PDUSessionResourceSetupRequestTransferIEs_t));
ASN_SEQUENCE_ADD(&message.protocolIEs, ie);
@ -132,7 +132,7 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_setup_request_transfer(
qosCharacteristics->choice.nonDynamic5QI = nonDynamic5QI;
qosCharacteristics->present = NGAP_QosCharacteristics_PR_nonDynamic5QI;
*qosFlowIdentifier = bearer->qfi;
*qosFlowIdentifier = qos_flow->qfi;
nonDynamic5QI->fiveQI = sess->pdn.qos.qci;

View File

@ -26,11 +26,11 @@ int ngap_handle_pdu_session_resource_setup_response_transfer(
{
ogs_sbi_session_t *session = NULL;
smf_ue_t *smf_ue = NULL;
smf_bearer_t *bearer = NULL;
smf_bearer_t *qos_flow = NULL;
int rv, i;
uint32_t gnb_n3_teid;
ogs_ip_t gnb_n3_ip;
uint32_t upf_n3_teid;
ogs_ip_t upf_n3_ip;
ogs_pfcp_far_t *far = NULL;
bool far_update = false;
@ -48,8 +48,6 @@ int ngap_handle_pdu_session_resource_setup_response_transfer(
ogs_assert(sess);
session = sess->sbi.session;
ogs_assert(session);
bearer = smf_default_bearer_in_sess(sess);
ogs_assert(bearer);
smf_ue = sess->smf_ue;
ogs_assert(smf_ue);
@ -90,10 +88,19 @@ int ngap_handle_pdu_session_resource_setup_response_transfer(
associatedQosFlowItem = (NGAP_AssociatedQosFlowItem_t *)
associatedQosFlowList->list.array[i];
if (associatedQosFlowItem) {
/* TODO : associatedQosFlowItem->qosFlowIdentifier */
qos_flow = smf_qos_flow_find_by_qfi(sess,
associatedQosFlowItem->qosFlowIdentifier);
}
}
if (!qos_flow) {
ogs_error("[%s:%d] No QoS flow", smf_ue->supi, sess->psi);
smf_sbi_send_sm_context_update_error(session,
OGS_SBI_HTTP_STATUS_BAD_REQUEST,
"No QoS flow", smf_ue->supi, NULL, NULL);
goto cleanup;
}
gTPTunnel = uPTransportLayerInformation->choice.gTPTunnel;
if (!gTPTunnel) {
ogs_error("[%s:%d] No GTPTunnel", smf_ue->supi, sess->psi);
@ -104,20 +111,20 @@ int ngap_handle_pdu_session_resource_setup_response_transfer(
}
ogs_asn_BIT_STRING_to_ip(
&gTPTunnel->transportLayerAddress, &gnb_n3_ip);
ogs_asn_OCTET_STRING_to_uint32(&gTPTunnel->gTP_TEID, &gnb_n3_teid);
&gTPTunnel->transportLayerAddress, &upf_n3_ip);
ogs_asn_OCTET_STRING_to_uint32(&gTPTunnel->gTP_TEID, &upf_n3_teid);
if (memcmp(&bearer->gnb_n3_ip, &gnb_n3_ip,
sizeof(bearer->gnb_n3_ip)) != 0 ||
bearer->gnb_n3_teid != gnb_n3_teid)
if (memcmp(&sess->gnb_n3_ip, &upf_n3_ip, sizeof(sess->gnb_n3_ip)) != 0 ||
sess->gnb_n3_teid != upf_n3_teid)
sess->pfcp_5gc_modify.outer_header_creation_update = true;
else
sess->pfcp_5gc_modify.outer_header_creation_update = false;
memcpy(&bearer->gnb_n3_ip, &gnb_n3_ip, sizeof(bearer->gnb_n3_ip));
bearer->gnb_n3_teid = gnb_n3_teid;
memcpy(&sess->gnb_n3_ip, &upf_n3_ip, sizeof(sess->gnb_n3_ip));
sess->gnb_n3_teid = upf_n3_teid;
ogs_list_for_each(&bearer->pfcp.far_list, far) {
/* Need to Update? */
ogs_list_for_each(&qos_flow->pfcp.far_list, far) {
if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) {
if (sess->ueUpCnxState == OpenAPI_up_cnx_state_ACTIVATED) {
if (far->apply_action != OGS_PFCP_APPLY_ACTION_FORW) {
@ -129,6 +136,15 @@ int ngap_handle_pdu_session_resource_setup_response_transfer(
}
}
/* Setup FAR */
ogs_list_for_each(&qos_flow->pfcp.far_list, far) {
if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) {
ogs_pfcp_ip_to_outer_header_creation(&sess->gnb_n3_ip,
&far->outer_header_creation, &far->outer_header_creation_len);
far->outer_header_creation.teid = sess->gnb_n3_teid;
}
}
if (far_update || sess->pfcp_5gc_modify.outer_header_creation_update)
smf_5gc_pfcp_send_session_modification_request(sess);
else

View File

@ -26,9 +26,9 @@ bool smf_nudm_sdm_handle_get(smf_sess_t *sess, ogs_sbi_message_t *recvmsg)
char buf2[OGS_ADDRSTRLEN];
smf_ue_t *smf_ue = NULL;
ogs_pfcp_subnet_t *subnet6 = NULL;
smf_bearer_t *bearer = NULL;
smf_bearer_t *qos_flow = NULL;
ogs_pfcp_gtpu_resource_t *resource = NULL;
ogs_pfcp_pdr_t *pdr = NULL;
ogs_pfcp_qer_t *qer = NULL;
@ -225,6 +225,59 @@ bool smf_nudm_sdm_handle_get(smf_sess_t *sess, ogs_sbi_message_t *recvmsg)
return false;
}
/* Select UPF based on UE Location Information */
smf_sess_select_upf(sess);
/* Check if selected UPF is associated with SMF */
ogs_assert(sess->pfcp_node);
if (!OGS_FSM_CHECK(&sess->pfcp_node->sm, smf_pfcp_state_associated)) {
ogs_error("[%s] No associated UPF", smf_ue->supi);
return false;
}
/* Setup GTP-U Tunnel */
resource = ogs_pfcp_gtpu_resource_find(
&sess->pfcp_node->gtpu_resource_list,
sess->pdn.dnn, OGS_PFCP_INTERFACE_ACCESS);
if (resource) {
ogs_pfcp_user_plane_ip_resource_info_to_sockaddr(&resource->info,
&sess->upf_n3_addr, &sess->upf_n3_addr6);
ogs_assert(sess->upf_n3_addr || sess->upf_n3_addr6);
if (resource->info.teidri)
sess->upf_n3_teid = UPF_GTPU_INDEX_TO_TEID(
sess->index, resource->info.teidri,
resource->info.teid_range);
else
sess->upf_n3_teid = sess->index;
} else {
if (sess->pfcp_node->addr.ogs_sa_family == AF_INET)
ogs_copyaddrinfo(&sess->upf_n3_addr, &sess->pfcp_node->addr);
else if (sess->pfcp_node->addr.ogs_sa_family == AF_INET6)
ogs_copyaddrinfo(&sess->upf_n3_addr6, &sess->pfcp_node->addr);
else
ogs_assert_if_reached();
ogs_assert(sess->upf_n3_addr || sess->upf_n3_addr6);
sess->upf_n3_teid = sess->index;
}
ogs_debug("UPF TEID:[0x%x], IPv4:[%s] IPv6:[%s]",
sess->upf_n3_teid,
sess->upf_n3_addr ? OGS_ADDR(sess->upf_n3_addr, buf1) : "",
sess->upf_n3_addr6 ? OGS_ADDR(sess->upf_n3_addr6, buf2) : "");
/* UE IP Address */
smf_sess_set_ue_ip(sess);
ogs_info("UE SUPI:[%s] DNN:[%s] IPv4:[%s] IPv6:[%s]",
smf_ue->supi, sess->pdn.dnn,
sess->ipv4 ? OGS_INET_NTOP(&sess->ipv4->addr, buf1) : "",
sess->ipv6 ? OGS_INET6_NTOP(&sess->ipv6->addr, buf2) : "");
/*********************************************************************
* Send HTTP_STATUS_CREATED(/nsmf-pdusession/v1/sm-context) to the AMF
*********************************************************************/
memset(&SmContextCreatedData, 0, sizeof(SmContextCreatedData));
memset(&sendmsg, 0, sizeof(sendmsg));
@ -246,84 +299,44 @@ bool smf_nudm_sdm_handle_get(smf_sess_t *sess, ogs_sbi_message_t *recvmsg)
ogs_free(sendmsg.http.location);
sess->pdn.paa.pdn_type = sess->pdn.pdn_type;
ogs_assert(sess->pdn.pdn_type);
if (sess->ipv4) {
ogs_hash_set(smf_self()->ipv4_hash,
sess->ipv4->addr, OGS_IPV4_LEN, NULL);
ogs_pfcp_ue_ip_free(sess->ipv4);
}
if (sess->ipv6) {
ogs_hash_set(smf_self()->ipv6_hash,
sess->ipv6->addr, OGS_IPV6_LEN, NULL);
ogs_pfcp_ue_ip_free(sess->ipv6);
/*********************************************************************
* Send PFCP Session Establiashment Request to the UPF
*********************************************************************/
/* Remove all previous QoS flow */
smf_bearer_remove_all(sess);
/* Setup Default QoS flow */
qos_flow = smf_qos_flow_add(sess);
ogs_assert(qos_flow);
/* Setup QER */
ogs_list_for_each(&qos_flow->pfcp.qer_list, qer) {
qer->mbr.uplink = sess->pdn.ambr.uplink;
qer->mbr.downlink = sess->pdn.ambr.downlink;
}
if (sess->pdn.pdn_type == OGS_PDU_SESSION_TYPE_IPV4) {
sess->ipv4 = ogs_pfcp_ue_ip_alloc(
AF_INET, sess->pdn.apn, (uint8_t *)&sess->pdn.ue_ip.addr);
ogs_assert(sess->ipv4);
sess->pdn.paa.addr = sess->ipv4->addr[0];
ogs_hash_set(smf_self()->ipv4_hash,
sess->ipv4->addr, OGS_IPV4_LEN, sess);
} else if (sess->pdn.pdn_type == OGS_PDU_SESSION_TYPE_IPV6) {
sess->ipv6 = ogs_pfcp_ue_ip_alloc(
AF_INET6, sess->pdn.apn, sess->pdn.ue_ip.addr6);
ogs_assert(sess->ipv6);
/* Setup PDR */
ogs_list_for_each(&qos_flow->pfcp.pdr_list, pdr) {
subnet6 = sess->ipv6->subnet;
ogs_assert(subnet6);
/* Set UE IP Address to the Default DL PDR */
if (pdr->src_if == OGS_PFCP_INTERFACE_CORE) {
ogs_pfcp_paa_to_ue_ip_addr(&sess->pdn.paa,
&pdr->ue_ip_addr, &pdr->ue_ip_addr_len);
pdr->ue_ip_addr.sd = OGS_PFCP_UE_IP_DST;
sess->pdn.paa.len = subnet6->prefixlen;
memcpy(sess->pdn.paa.addr6, sess->ipv6->addr, OGS_IPV6_LEN);
ogs_hash_set(smf_self()->ipv6_hash,
sess->ipv6->addr, OGS_IPV6_LEN, sess);
} else if (sess->pdn.pdn_type == OGS_PDU_SESSION_TYPE_IPV4V6) {
sess->ipv4 = ogs_pfcp_ue_ip_alloc(
AF_INET, sess->pdn.apn, (uint8_t *)&sess->pdn.ue_ip.addr);
ogs_assert(sess->ipv4);
sess->ipv6 = ogs_pfcp_ue_ip_alloc(
AF_INET6, sess->pdn.apn, sess->pdn.ue_ip.addr6);
ogs_assert(sess->ipv6);
/* Set UPF-N3 TEID & ADDR to the Default UL PDR */
} else if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS) {
ogs_pfcp_sockaddr_to_f_teid(sess->upf_n3_addr, sess->upf_n3_addr6,
&pdr->f_teid, &pdr->f_teid_len);
pdr->f_teid.teid = sess->upf_n3_teid;
}
subnet6 = sess->ipv6->subnet;
ogs_assert(subnet6);
sess->pdn.paa.both.addr = sess->ipv4->addr[0];
sess->pdn.paa.both.len = subnet6->prefixlen;
memcpy(sess->pdn.paa.both.addr6, sess->ipv6->addr, OGS_IPV6_LEN);
ogs_hash_set(smf_self()->ipv4_hash,
sess->ipv4->addr, OGS_IPV4_LEN, sess);
ogs_hash_set(smf_self()->ipv6_hash,
sess->ipv6->addr, OGS_IPV6_LEN, sess);
} else
ogs_assert_if_reached();
ogs_info("UE SUPI:[%s] DNN:[%s] IPv4:[%s] IPv6:[%s]",
smf_ue->supi, sess->pdn.apn,
sess->ipv4 ? OGS_INET_NTOP(&sess->ipv4->addr, buf1) : "",
sess->ipv6 ? OGS_INET6_NTOP(&sess->ipv6->addr, buf2) : "");
bearer = smf_default_bearer_in_sess(sess);
ogs_assert(bearer);
/* Only 1 QER is used per bearer */
qer = ogs_list_first(&bearer->pfcp.qer_list);
if (!qer) {
qer = ogs_pfcp_qer_add(&bearer->pfcp);
ogs_assert(qer);
qer->id = OGS_NEXT_ID(sess->qer_id, 1, OGS_MAX_NUM_OF_QER+1);
/* Default PDRs is set to lowest precedence(highest precedence value) */
pdr->precedence = 0xffffffff;
}
qer->mbr.uplink = sess->pdn.ambr.uplink;
qer->mbr.downlink = sess->pdn.ambr.downlink;
qer->qfi = bearer->qfi;
ogs_list_for_each(&bearer->pfcp.pdr_list, pdr)
ogs_pfcp_pdr_associate_qer(pdr, qer);
smf_5gc_pfcp_send_session_establishment_request(sess);
return true;

View File

@ -32,7 +32,10 @@ ogs_pkbuf_t *smf_s5c_build_create_session_response(
ogs_gtp_create_session_response_t *rsp = NULL;
ogs_gtp_cause_t cause;
ogs_gtp_f_teid_t smf_s5c_teid, upf_n3_teid;
ogs_gtp_f_teid_t smf_s5c_teid, upf_s5u_teid;
ogs_gtp_ambr_t ambr;
ogs_gtp_bearer_qos_t bearer_qos;
char bearer_qos_buf[GTP_BEARER_QOS_LEN];
int len;
uint8_t pco_buf[OGS_MAX_PCO_LEN];
int16_t pco_len;
@ -45,8 +48,8 @@ ogs_pkbuf_t *smf_s5c_build_create_session_response(
ogs_debug(" SGW_S5C_TEID[0x%x] SMF_N4_TEID[0x%x]",
sess->sgw_s5c_teid, sess->smf_n4_teid);
ogs_debug(" gNB_N3_TEID[0x%x] UPF_N3_TEID[0x%x]",
bearer->gnb_n3_teid, bearer->upf_n3_teid);
ogs_debug(" SGW_S5U_TEID[0x%x] UPF_S5U_TEID[0x%x]",
bearer->sgw_s5u_teid, bearer->upf_s5u_teid);
rsp = &gtp_message.create_session_response;
memset(&gtp_message, 0, sizeof(ogs_gtp_message_t));
@ -88,8 +91,16 @@ ogs_pkbuf_t *smf_s5c_build_create_session_response(
rsp->apn_restriction.presence = 1;
rsp->apn_restriction.u8 = OGS_GTP_APN_NO_RESTRICTION;
/* TODO : APN-AMBR
/* APN-AMBR
* if PCRF changes APN-AMBR, this should be included. */
if (sess->gtp_5gc.create_session_response_apn_ambr == true) {
memset(&ambr, 0, sizeof(ogs_gtp_ambr_t));
ambr.uplink = htobe32(sess->pdn.ambr.uplink / 1000);
ambr.downlink = htobe32(sess->pdn.ambr.downlink / 1000);
rsp->aggregate_maximum_bit_rate.presence = 1;
rsp->aggregate_maximum_bit_rate.data = &ambr;
rsp->aggregate_maximum_bit_rate.len = sizeof(ambr);
}
/* PCO */
if (sess->gtp.ue_pco.presence &&
@ -112,18 +123,31 @@ ogs_pkbuf_t *smf_s5c_build_create_session_response(
rsp->bearer_contexts_created.cause.len = sizeof(cause);
rsp->bearer_contexts_created.cause.data = &cause;
/* TODO : Bearer QoS
/* Bearer QoS
* if PCRF changes Bearer QoS, this should be included. */
if (sess->gtp_5gc.create_session_response_bearer_qos == true) {
memset(&bearer_qos, 0, sizeof(bearer_qos));
bearer_qos.qci = sess->pdn.qos.qci;
bearer_qos.priority_level = sess->pdn.qos.arp.priority_level;
bearer_qos.pre_emption_capability =
sess->pdn.qos.arp.pre_emption_capability;
bearer_qos.pre_emption_vulnerability =
sess->pdn.qos.arp.pre_emption_vulnerability;
rsp->bearer_contexts_created.bearer_level_qos.presence = 1;
ogs_gtp_build_bearer_qos(&rsp->bearer_contexts_created.bearer_level_qos,
&bearer_qos, bearer_qos_buf, GTP_BEARER_QOS_LEN);
}
/* Data Plane(UL) : SMF-S5U */
memset(&upf_n3_teid, 0, sizeof(ogs_gtp_f_teid_t));
upf_n3_teid.interface_type = OGS_GTP_F_TEID_S5_S8_PGW_GTP_U;
upf_n3_teid.teid = htobe32(bearer->upf_n3_teid);
memset(&upf_s5u_teid, 0, sizeof(ogs_gtp_f_teid_t));
upf_s5u_teid.interface_type = OGS_GTP_F_TEID_S5_S8_PGW_GTP_U;
upf_s5u_teid.teid = htobe32(bearer->upf_s5u_teid);
rv = ogs_gtp_sockaddr_to_f_teid(
bearer->upf_addr, bearer->upf_addr6, &upf_n3_teid, &len);
bearer->upf_s5u_addr, bearer->upf_s5u_addr6, &upf_s5u_teid, &len);
ogs_assert(rv == OGS_OK);
rsp->bearer_contexts_created.s5_s8_u_sgw_f_teid.presence = 1;
rsp->bearer_contexts_created.s5_s8_u_sgw_f_teid.data = &upf_n3_teid;
rsp->bearer_contexts_created.s5_s8_u_sgw_f_teid.data = &upf_s5u_teid;
rsp->bearer_contexts_created.s5_s8_u_sgw_f_teid.len = len;
gtp_message.h.type = type;
@ -182,7 +206,7 @@ ogs_pkbuf_t *smf_s5c_build_create_bearer_request(
ogs_gtp_message_t gtp_message;
ogs_gtp_create_bearer_request_t *req = NULL;
ogs_gtp_f_teid_t upf_n3_teid;
ogs_gtp_f_teid_t upf_s5u_teid;
ogs_gtp_bearer_qos_t bearer_qos;
char bearer_qos_buf[GTP_BEARER_QOS_LEN];
int len;
@ -211,14 +235,14 @@ ogs_pkbuf_t *smf_s5c_build_create_bearer_request(
req->bearer_contexts.eps_bearer_id.u8 = bearer->ebi;
/* Data Plane(UL) : SMF_S5U */
memset(&upf_n3_teid, 0, sizeof(ogs_gtp_f_teid_t));
upf_n3_teid.interface_type = OGS_GTP_F_TEID_S5_S8_PGW_GTP_U;
upf_n3_teid.teid = htobe32(bearer->upf_n3_teid);
memset(&upf_s5u_teid, 0, sizeof(ogs_gtp_f_teid_t));
upf_s5u_teid.interface_type = OGS_GTP_F_TEID_S5_S8_PGW_GTP_U;
upf_s5u_teid.teid = htobe32(bearer->upf_s5u_teid);
rv = ogs_gtp_sockaddr_to_f_teid(
bearer->upf_addr, bearer->upf_addr6, &upf_n3_teid, &len);
bearer->upf_s5u_addr, bearer->upf_s5u_addr6, &upf_s5u_teid, &len);
ogs_assert(rv == OGS_OK);
req->bearer_contexts.s5_s8_u_sgw_f_teid.presence = 1;
req->bearer_contexts.s5_s8_u_sgw_f_teid.data = &upf_n3_teid;
req->bearer_contexts.s5_s8_u_sgw_f_teid.data = &upf_s5u_teid;
req->bearer_contexts.s5_s8_u_sgw_f_teid.len = len;
/* Bearer QoS */

View File

@ -49,9 +49,18 @@ void smf_s5c_handle_create_session_request(
smf_sess_t *sess, ogs_gtp_xact_t *xact,
ogs_gtp_create_session_request_t *req)
{
char buf1[OGS_ADDRSTRLEN];
char buf2[OGS_ADDRSTRLEN];
int rv;
uint8_t cause_value = 0;
ogs_gtp_f_teid_t *sgw_s5c_teid, *gnb_n3_teid;
char apn[OGS_MAX_APN_LEN];
ogs_gtp_uli_t uli;
smf_ue_t *smf_ue = NULL;
ogs_gtp_f_teid_t *sgw_s5c_teid, *sgw_s5u_teid;
smf_bearer_t *bearer = NULL;
ogs_gtp_bearer_qos_t bearer_qos;
ogs_gtp_ambr_t *ambr = NULL;
@ -64,12 +73,8 @@ void smf_s5c_handle_create_session_request(
cause_value = OGS_GTP_CAUSE_REQUEST_ACCEPTED;
if (sess) {
bearer = smf_default_bearer_in_sess(sess);
ogs_assert(bearer);
}
if (!bearer) {
ogs_warn("No Context");
if (!sess) {
ogs_error("No Context");
cause_value = OGS_GTP_CAUSE_CONTEXT_NOT_FOUND;
}
@ -85,6 +90,10 @@ void smf_s5c_handle_create_session_request(
ogs_error("No Bearer");
cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING;
}
if (req->bearer_contexts_to_be_created.eps_bearer_id.presence == 0) {
ogs_error("No EPS Bearer ID");
cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING;
}
if (req->bearer_contexts_to_be_created.bearer_level_qos.presence == 0) {
ogs_error("No EPS Bearer QoS");
cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING;
@ -93,6 +102,18 @@ void smf_s5c_handle_create_session_request(
ogs_error("No TEID");
cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING;
}
if (req->pdn_type.presence == 0) {
ogs_error("No PDN Type");
cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING;
}
if (req->pdn_address_allocation.presence == 0) {
ogs_error("No PAA");
cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING;
}
if (req->user_location_information.presence == 0) {
ogs_error("No UE Location Information");
cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING;
}
if (!ogs_diam_peer_connected()) {
ogs_error("No Diameter Peer");
@ -104,28 +125,67 @@ void smf_s5c_handle_create_session_request(
OGS_GTP_CREATE_SESSION_RESPONSE_TYPE, cause_value);
return;
}
/* Set IMSI */
sess->imsi_len = req->imsi.len;
memcpy(sess->imsi, req->imsi.data, sess->imsi_len);
ogs_buffer_to_bcd(sess->imsi, sess->imsi_len, sess->imsi_bcd);
ogs_assert(sess);
smf_ue = sess->smf_ue;
ogs_assert(smf_ue);
/* UE Location Inforamtion*/
ogs_gtp_parse_uli(&uli, &req->user_location_information);
memcpy(&sess->e_tai, &uli.tai, sizeof(sess->e_tai));
memcpy(&sess->e_cgi, &uli.e_cgi, sizeof(sess->e_cgi));
/* Select UPF based on UE Location Information */
smf_sess_select_upf(sess);
/* Check if selected UPF is associated with SMF */
ogs_assert(sess->pfcp_node);
if (!OGS_FSM_CHECK(&sess->pfcp_node->sm, smf_pfcp_state_associated)) {
ogs_gtp_send_error_message(xact, sess ? sess->sgw_s5c_teid : 0,
OGS_GTP_CREATE_SESSION_RESPONSE_TYPE,
OGS_GTP_CAUSE_REMOTE_PEER_NOT_RESPONDING);
return;
}
/* UE IP Address */
ogs_assert(req->pdn_address_allocation.data);
sess->pdn.pdn_type = req->pdn_type.u8;
ogs_gtp_paa_to_ip(
(ogs_paa_t *)req->pdn_address_allocation.data, &sess->pdn.ue_ip);
smf_sess_set_ue_ip(sess);
ogs_info("UE IMSI:[%s] APN:[%s] IPv4:[%s] IPv6:[%s]",
smf_ue->imsi_bcd, apn,
sess->ipv4 ? OGS_INET_NTOP(&sess->ipv4->addr, buf1) : "",
sess->ipv6 ? OGS_INET6_NTOP(&sess->ipv6->addr, buf2) : "");
/* Remove all previous bearer */
smf_bearer_remove_all(sess);
/* Setup Default Bearer */
bearer = smf_bearer_add(sess);
ogs_assert(bearer);
/* Set Bearer EBI */
bearer->ebi = req->bearer_contexts_to_be_created.eps_bearer_id.u8;
/* Control Plane(DL) : SGW-S5C */
sgw_s5c_teid = req->sender_f_teid_for_control_plane.data;
ogs_assert(sgw_s5c_teid);
sess->sgw_s5c_teid = be32toh(sgw_s5c_teid->teid);
/* Data Plane(DL) : gNB-N3 */
gnb_n3_teid = req->bearer_contexts_to_be_created.s5_s8_u_sgw_f_teid.data;
ogs_assert(gnb_n3_teid);
bearer->gnb_n3_teid = be32toh(gnb_n3_teid->teid);
rv = ogs_gtp_f_teid_to_ip(gnb_n3_teid, &bearer->gnb_n3_ip);
/* Data Plane(DL) : SGW-S5U */
sgw_s5u_teid = req->bearer_contexts_to_be_created.s5_s8_u_sgw_f_teid.data;
ogs_assert(sgw_s5u_teid);
bearer->sgw_s5u_teid = be32toh(sgw_s5u_teid->teid);
rv = ogs_gtp_f_teid_to_ip(sgw_s5u_teid, &bearer->sgw_s5u_ip);
ogs_assert(rv == OGS_OK);
ogs_debug(" SGW_S5C_TEID[0x%x] SMF_N4_TEID[0x%x]",
sess->sgw_s5c_teid, sess->smf_n4_teid);
ogs_debug(" gNB_N3_TEID[0x%x] UPF_N3_TEID[0x%x]",
bearer->gnb_n3_teid, bearer->upf_n3_teid);
ogs_debug(" SGW_S5U_TEID[0x%x] UPF_S5U_TEID[0x%x]",
bearer->sgw_s5u_teid, bearer->upf_s5u_teid);
decoded = ogs_gtp_parse_bearer_qos(&bearer_qos,
&req->bearer_contexts_to_be_created.bearer_level_qos);
@ -168,7 +228,7 @@ void smf_s5c_handle_create_session_request(
if (req->ue_time_zone.presence) {
OGS_TLV_STORE_DATA(&sess->gtp.ue_timezone, &req->ue_time_zone);
}
smf_gx_send_ccr(sess, xact,
OGS_DIAM_GX_CC_REQUEST_TYPE_INITIAL_REQUEST);
}
@ -214,8 +274,9 @@ void smf_s5c_handle_create_bearer_response(
ogs_gtp_create_bearer_response_t *rsp)
{
int rv;
ogs_gtp_f_teid_t *gnb_n3_teid, *smf_s5u_teid;
ogs_gtp_f_teid_t *sgw_s5u_teid, *smf_s5u_teid;
smf_bearer_t *bearer = NULL;
ogs_pfcp_far_t *far = NULL;
ogs_assert(xact);
ogs_assert(rsp);
@ -271,16 +332,26 @@ void smf_s5c_handle_create_bearer_response(
/* Set EBI */
bearer->ebi = rsp->bearer_contexts.eps_bearer_id.u8;
/* Data Plane(DL) : gNB-N3 */
gnb_n3_teid = rsp->bearer_contexts.s5_s8_u_sgw_f_teid.data;
ogs_assert(gnb_n3_teid);
bearer->gnb_n3_teid = be32toh(gnb_n3_teid->teid);
rv = ogs_gtp_f_teid_to_ip(gnb_n3_teid, &bearer->gnb_n3_ip);
/* Data Plane(DL) : SGW-S5U */
sgw_s5u_teid = rsp->bearer_contexts.s5_s8_u_sgw_f_teid.data;
ogs_assert(sgw_s5u_teid);
bearer->sgw_s5u_teid = be32toh(sgw_s5u_teid->teid);
rv = ogs_gtp_f_teid_to_ip(sgw_s5u_teid, &bearer->sgw_s5u_ip);
ogs_assert(rv == OGS_OK);
ogs_debug("[SMF] Create Bearer Response : SGW[0x%x] --> SMF[0x%x]",
sess->sgw_s5c_teid, sess->smf_n4_teid);
/* Setup FAR */
ogs_list_for_each(&bearer->pfcp.far_list, far) {
if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) {
ogs_pfcp_ip_to_outer_header_creation(&bearer->sgw_s5u_ip,
&far->outer_header_creation, &far->outer_header_creation_len);
far->outer_header_creation.teid = bearer->sgw_s5u_teid;
}
}
/* Setup QER */
if (bearer->qos.mbr.downlink || bearer->qos.mbr.uplink ||
bearer->qos.gbr.downlink || bearer->qos.gbr.uplink) {
ogs_pfcp_pdr_t *pdr = NULL;

View File

@ -28,19 +28,6 @@ static OGS_POOL(upf_sdf_filter_pool, upf_sdf_filter_t);
static int context_initialized = 0;
int num_sessions = 0;
void stats_add_session(void) {
num_sessions = num_sessions + 1;
ogs_info("Added a session. Number of active sessions is now %d",
num_sessions);
}
void stats_remove_session(void) {
num_sessions = num_sessions - 1;
ogs_info("Removed a session. Number of active sessions is now %d",
num_sessions);
}
void upf_context_init(void)
{
ogs_assert(context_initialized == 0);
@ -457,7 +444,7 @@ upf_sess_t *upf_sess_add(ogs_pfcp_f_seid_t *cp_f_seid,
OGS_SETUP_DEFAULT_PDR(&sess->pfcp,
ogs_pfcp_pdr_find_or_add(&sess->pfcp, default_pdr_id));
ogs_info("UE F-SEID[CP:%ld,UP:%ld] "
ogs_info("UE F-SEID[CP:0x%lx,UP:0x%lx] "
"APN[%s] PDN-Type[%d] IPv4[%s] IPv6[%s], Default PDR ID[%d]",
(long)sess->upf_n4_seid, (long)sess->smf_n4_seid,
apn, pdn_type,
@ -467,7 +454,8 @@ upf_sess_t *upf_sess_add(ogs_pfcp_f_seid_t *cp_f_seid,
ogs_list_add(&self.sess_list, sess);
stats_add_session();
ogs_info("Added a session. Number of active sessions is now %d",
ogs_list_count(&self.sess_list));
return sess;
@ -498,7 +486,8 @@ int upf_sess_remove(upf_sess_t *sess)
ogs_pool_free(&upf_sess_pool, sess);
stats_remove_session();
ogs_info("Removed a session. Number of active sessions is now %d",
ogs_list_count(&self.sess_list));
return OGS_OK;
}

View File

@ -120,9 +120,6 @@ upf_sdf_filter_t *upf_sdf_filter_add(ogs_pfcp_pdr_t *pdr);
void upf_sdf_filter_remove(upf_sdf_filter_t *sdf_filter);
void upf_sdf_filter_remove_all(upf_sess_t *sess);
void stats_add_session(void);
void stats_remove_session(void);
#ifdef __cplusplus
}
#endif

View File

@ -41,7 +41,7 @@
#define UPF_GTP_HANDLED 1
static void upf_gtp_send_to_gnb(ogs_pfcp_far_t *far, ogs_pkbuf_t *sendbuf);
static void upf_gtp_send_to_gnb(ogs_pfcp_pdr_t *pdr, ogs_pkbuf_t *sendbuf);
static int upf_gtp_handle_multicast(ogs_pkbuf_t *recvbuf);
static int upf_gtp_handle_slaac(upf_sess_t *sess, ogs_pkbuf_t *recvbuf);
static int upf_gtp_handle_pdr(ogs_pfcp_pdr_t *pdr, ogs_pkbuf_t *recvbuf);
@ -94,6 +94,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
struct ip *ip_h = NULL;
uint32_t teid;
uint8_t qfi;
ogs_pfcp_pdr_t *pdr = NULL;
upf_sess_t *sess = NULL;
ogs_pfcp_subnet_t *subnet = NULL;
@ -166,6 +167,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
ogs_debug("[RECV] GPU-U from [%s] : TEID[0x%x]",
OGS_ADDR(&from, buf), teid);
qfi = 0;
if (gtp_h->flags & OGS_GTPU_FLAGS_E) {
/*
* TS29.281
@ -184,6 +186,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
OGS_GTP_EXTENSION_HEADER_PDU_TYPE_UL_PDU_SESSION_INFORMATION) {
ogs_debug(" QFI [0x%x]",
extension_header->qos_flow_identifier);
qfi = extension_header->qos_flow_identifier;
}
}
}
@ -200,9 +203,10 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
ip_h = (struct ip *)pkbuf->data;
ogs_assert(ip_h);
pdr = ogs_pfcp_pdr_find_by_teid(teid);
pdr = ogs_pfcp_pdr_find_by_teid_and_qfi(teid, qfi);
if (!pdr) {
ogs_warn("[DROP] Cannot find PDR : UPF-N3-TEID[0x%x]", teid);
ogs_warn("[DROP] Cannot find PDR : UPF-N3-TEID[0x%x] QFI[%d]",
teid, qfi);
goto cleanup;
}
ogs_assert(pdr->sess);
@ -326,23 +330,25 @@ void upf_gtp_close(void)
}
}
void upf_gtp_send_buffered_packet(ogs_pfcp_far_t *far)
void upf_gtp_send_buffered_packet(ogs_pfcp_pdr_t *pdr)
{
ogs_pfcp_far_t *far = NULL;
int i;
ogs_assert(far);
ogs_assert(pdr);
far = pdr->far;
if (far->gnode) {
if (far && far->gnode) {
if (far->apply_action & OGS_PFCP_APPLY_ACTION_FORW) {
for (i = 0; i < far->num_of_buffered_packet; i++) {
upf_gtp_send_to_gnb(far, far->buffered_packet[i]);
upf_gtp_send_to_gnb(pdr, far->buffered_packet[i]);
}
far->num_of_buffered_packet = 0;
}
}
}
static void upf_gtp_send_to_gnb(ogs_pfcp_far_t *far, ogs_pkbuf_t *sendbuf)
static void upf_gtp_send_to_gnb(ogs_pfcp_pdr_t *pdr, ogs_pkbuf_t *sendbuf)
{
char buf[OGS_ADDRSTRLEN];
int rv;
@ -350,10 +356,16 @@ static void upf_gtp_send_to_gnb(ogs_pfcp_far_t *far, ogs_pkbuf_t *sendbuf)
ogs_gtp_extension_header_t *ext_h = NULL;
ogs_gtp_node_t *gnode = NULL;
ogs_pfcp_pdr_t *pdr = NULL;
ogs_pfcp_far_t *far = NULL;
ogs_pfcp_qer_t *qer = NULL;
ogs_assert(far);
ogs_assert(pdr);
far = pdr->far;
if (!far) {
ogs_error("No FAR");
return;
}
if (far->dst_if != OGS_PFCP_INTERFACE_ACCESS) {
ogs_error("FAR is NOT Downlink");
@ -365,8 +377,6 @@ static void upf_gtp_send_to_gnb(ogs_pfcp_far_t *far, ogs_pkbuf_t *sendbuf)
ogs_assert(gnode->sock);
ogs_assert(sendbuf);
pdr = far->pdr;
ogs_assert(pdr);
qer = pdr->qer;
/* Add GTP-U header */
@ -444,7 +454,7 @@ static int upf_gtp_handle_pdr(ogs_pfcp_pdr_t *pdr, ogs_pkbuf_t *recvbuf)
}
} else {
if (far->apply_action & OGS_PFCP_APPLY_ACTION_FORW) {
upf_gtp_send_to_gnb(far, sendbuf);
upf_gtp_send_to_gnb(pdr, sendbuf);
} else if (far->apply_action & OGS_PFCP_APPLY_ACTION_BUFF) {
if (far->num_of_buffered_packet < MAX_NUM_OF_PACKET_BUFFER) {
far->buffered_packet[far->num_of_buffered_packet++] = sendbuf;

View File

@ -30,7 +30,7 @@ extern "C" {
int upf_gtp_open(void);
void upf_gtp_close(void);
void upf_gtp_send_buffered_packet(ogs_pfcp_far_t *far);
void upf_gtp_send_buffered_packet(ogs_pfcp_pdr_t *pdr);
#ifdef __cplusplus
}

View File

@ -58,6 +58,40 @@ void upf_n4_handle_heartbeat_response(
upf_timer_cfg(UPF_TIMER_HEARTBEAT)->duration);
}
static void setup_gtp_node(ogs_pfcp_far_t *far,
ogs_pfcp_tlv_outer_header_creation_t *outer_header_creation)
{
int rv;
ogs_ip_t ip;
ogs_gtp_node_t *gnode = NULL;
ogs_assert(far);
ogs_assert(outer_header_creation);
ogs_assert(outer_header_creation->presence);
memcpy(&far->outer_header_creation,
outer_header_creation->data, outer_header_creation->len);
far->outer_header_creation.teid = be32toh(far->outer_header_creation.teid);
rv = ogs_pfcp_outer_header_creation_to_ip(&far->outer_header_creation, &ip);
ogs_assert(rv == OGS_OK);
gnode = ogs_gtp_node_find_by_ip(&upf_self()->gnb_n3_list, &ip);
if (!gnode) {
gnode = ogs_gtp_node_add_by_ip(
&upf_self()->gnb_n3_list, &ip, upf_self()->gtpu_port,
ogs_config()->parameter.no_ipv4,
ogs_config()->parameter.no_ipv6,
ogs_config()->parameter.prefer_ipv4);
ogs_assert(gnode);
rv = ogs_gtp_connect(
upf_self()->gtpu_sock, upf_self()->gtpu_sock6, gnode);
ogs_assert(rv == OGS_OK);
}
OGS_SETUP_GTP_NODE(far, gnode);
}
static ogs_pfcp_pdr_t *handle_create_pdr(ogs_pfcp_sess_t *sess,
ogs_pfcp_tlv_create_pdr_t *message,
uint8_t *cause_value, uint8_t *offending_ie_value)
@ -159,16 +193,13 @@ static ogs_pfcp_pdr_t *handle_create_pdr(ogs_pfcp_sess_t *sess,
return NULL;
}
memcpy(&pdr->f_teid, message->pdi.local_f_teid.data,
message->pdi.local_f_teid.len);
pdr->f_teid_len = message->pdi.local_f_teid.len;
memcpy(&pdr->f_teid, message->pdi.local_f_teid.data, pdr->f_teid_len);
pdr->f_teid.teid = be32toh(pdr->f_teid.teid);
memcpy(&pdr->outer_header_removal,
message->outer_header_removal.data,
message->outer_header_removal.len);
/* Setup UPF-N3-TEID */
ogs_hash_set(ogs_pfcp_self()->pdr_hash, &pdr->f_teid.teid,
sizeof(pdr->f_teid.teid), pdr);
} else {
ogs_error("Invalid Source Interface[%d] in PDR", pdr->src_if);
*cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_INCORRECT;
@ -264,40 +295,11 @@ static ogs_pfcp_far_t *handle_create_far(ogs_pfcp_sess_t *sess,
far->dst_if = message->forwarding_parameters.destination_interface.u8;
if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) { /* Downlink */
int rv;
ogs_ip_t ip;
ogs_gtp_node_t *gnode = NULL;
if (message->forwarding_parameters.outer_header_creation.presence) {
memcpy(&far->outer_header_creation,
message->forwarding_parameters.outer_header_creation.data,
message->forwarding_parameters.outer_header_creation.len);
far->outer_header_creation.teid =
be32toh(far->outer_header_creation.teid);
/* Setup GTP Node */
rv = ogs_pfcp_outer_header_creation_to_ip(
&far->outer_header_creation, &ip);
ogs_assert(rv == OGS_OK);
gnode = ogs_gtp_node_find_by_ip(&upf_self()->gnb_n3_list, &ip);
if (!gnode) {
gnode = ogs_gtp_node_add_by_ip(
&upf_self()->gnb_n3_list, &ip, upf_self()->gtpu_port,
ogs_config()->parameter.no_ipv4,
ogs_config()->parameter.no_ipv6,
ogs_config()->parameter.prefer_ipv4);
ogs_assert(gnode);
rv = ogs_gtp_connect(
upf_self()->gtpu_sock, upf_self()->gtpu_sock6, gnode);
ogs_assert(rv == OGS_OK);
}
OGS_SETUP_GTP_NODE(far, gnode);
setup_gtp_node(far,
&message->forwarding_parameters.outer_header_creation);
}
upf_gtp_send_buffered_packet(far);
} else if (far->dst_if == OGS_PFCP_INTERFACE_CORE) { /* Uplink */
/* Nothing */
@ -348,43 +350,12 @@ static ogs_pfcp_far_t *handle_update_far(ogs_pfcp_sess_t *sess,
destination_interface.u8;
if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) { /* Downlink */
int rv;
ogs_ip_t ip;
ogs_gtp_node_t *gnode = NULL;
if (message->update_forwarding_parameters.
outer_header_creation.presence) {
memcpy(&far->outer_header_creation,
message->update_forwarding_parameters.
outer_header_creation.data,
message->update_forwarding_parameters.
outer_header_creation.len);
far->outer_header_creation.teid =
be32toh(far->outer_header_creation.teid);
/* Setup GTP Node */
rv = ogs_pfcp_outer_header_creation_to_ip(
&far->outer_header_creation, &ip);
ogs_assert(rv == OGS_OK);
gnode = ogs_gtp_node_find_by_ip(&upf_self()->gnb_n3_list, &ip);
if (!gnode) {
gnode = ogs_gtp_node_add_by_ip(
&upf_self()->gnb_n3_list, &ip, upf_self()->gtpu_port,
ogs_config()->parameter.no_ipv4,
ogs_config()->parameter.no_ipv6,
ogs_config()->parameter.prefer_ipv4);
ogs_assert(gnode);
rv = ogs_gtp_connect(
upf_self()->gtpu_sock, upf_self()->gtpu_sock6, gnode);
ogs_assert(rv == OGS_OK);
}
OGS_SETUP_GTP_NODE(far, gnode);
setup_gtp_node(far,
&message->update_forwarding_parameters.outer_header_creation);
}
upf_gtp_send_buffered_packet(far);
} else if (far->dst_if == OGS_PFCP_INTERFACE_CORE) { /* Uplink */
/* Nothing */
@ -547,6 +518,7 @@ void upf_n4_handle_session_establishment_request(
upf_sess_t *sess, ogs_pfcp_xact_t *xact,
ogs_pfcp_session_establishment_request_t *req)
{
ogs_pfcp_pdr_t *pdr = NULL;
ogs_pfcp_pdr_t *created_pdr[OGS_MAX_NUM_OF_PDR];
int num_of_created_pdr = 0;
uint8_t cause_value = 0;
@ -594,6 +566,24 @@ void upf_n4_handle_session_establishment_request(
if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED)
goto cleanup;
/* Setup UPF-N3-TEID & QFI Hash */
for (i = 0; i < num_of_created_pdr; i++) {
pdr = created_pdr[i];
ogs_assert(pdr);
if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS) { /* Uplink */
if (pdr->f_teid_len)
ogs_pfcp_pdr_hash_set(pdr);
}
}
/* Send Buffered Packet to gNB/SGW */
ogs_list_for_each(&sess->pfcp.pdr_list, pdr) {
if (pdr->src_if == OGS_PFCP_INTERFACE_CORE) { /* Downlink */
upf_gtp_send_buffered_packet(pdr);
}
}
upf_pfcp_send_session_establishment_response(
xact, sess, created_pdr, num_of_created_pdr);
return;
@ -609,6 +599,7 @@ void upf_n4_handle_session_modification_request(
upf_sess_t *sess, ogs_pfcp_xact_t *xact,
ogs_pfcp_session_modification_request_t *req)
{
ogs_pfcp_pdr_t *pdr = NULL;
ogs_pfcp_pdr_t *created_pdr[OGS_MAX_NUM_OF_PDR];
int num_of_created_pdr = 0;
uint8_t cause_value = 0;
@ -696,6 +687,24 @@ void upf_n4_handle_session_modification_request(
if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED)
goto cleanup;
/* Setup UPF-N3-TEID & QFI Hash */
for (i = 0; i < num_of_created_pdr; i++) {
pdr = created_pdr[i];
ogs_assert(pdr);
if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS) { /* Uplink */
if (pdr->f_teid_len)
ogs_pfcp_pdr_hash_set(pdr);
}
}
/* Send Buffered Packet to gNB/SGW */
ogs_list_for_each(&sess->pfcp.pdr_list, pdr) {
if (pdr->src_if == OGS_PFCP_INTERFACE_CORE) { /* Downlink */
upf_gtp_send_buffered_packet(pdr);
}
}
upf_pfcp_send_session_modification_response(
xact, sess, created_pdr, num_of_created_pdr);
return;

View File

@ -205,6 +205,8 @@ typedef struct test_sess_s {
ogs_ip_t gnb_n3_ip;
uint32_t gnb_n3_teid;
uint8_t qfi;
test_ul_nas_transport_param_t ul_nas_transport_param;
test_ue_t *test_ue;

View File

@ -977,7 +977,7 @@ static ogs_pkbuf_t *testngap_build_pdu_session_resource_setup_response_trasfer(
CALLOC(1, sizeof(struct NGAP_AssociatedQosFlowItem));
ASN_SEQUENCE_ADD(&associatedQosFlowList->list, associatedQosFlowItem);
associatedQosFlowItem->qosFlowIdentifier = 1;
associatedQosFlowItem->qosFlowIdentifier = sess->qfi;
return ogs_asn_encode(
&asn_DEF_NGAP_PDUSessionResourceSetupResponseTransfer, &message);

View File

@ -158,7 +158,7 @@ void testngap_handle_pdu_session_resource_setup_request(
test_ue_t *test_ue, ogs_ngap_message_t *message)
{
test_sess_t *sess = NULL;
int rv, i, j, k;
int rv, i, j, k, l;
char buf[OGS_ADDRSTRLEN];
NGAP_NGAP_PDU_t pdu;
@ -176,6 +176,8 @@ void testngap_handle_pdu_session_resource_setup_request(
NGAP_UPTransportLayerInformation_t *UPTransportLayerInformation = NULL;
NGAP_GTPTunnel_t *gTPTunnel = NULL;
NGAP_PDUSessionType_t *PDUSessionType = NULL;
NGAP_QosFlowSetupRequestList_t *QosFlowSetupRequestList = NULL;
NGAP_QosFlowSetupRequestItem_t *QosFlowSetupRequestItem = NULL;
OCTET_STRING_t *transfer = NULL;
ogs_pkbuf_t *n2smbuf = NULL;
@ -219,6 +221,20 @@ void testngap_handle_pdu_session_resource_setup_request(
for (k = 0; k < n2sm_message.protocolIEs.list.count; k++) {
ie2 = n2sm_message.protocolIEs.list.array[k];
switch (ie2->id) {
case NGAP_ProtocolIE_ID_id_QosFlowSetupRequestList:
QosFlowSetupRequestList =
&ie2->value.choice.QosFlowSetupRequestList;
ogs_assert(QosFlowSetupRequestList);
for (l = 0;
l < QosFlowSetupRequestList->list.count; l++) {
QosFlowSetupRequestItem =
(struct NGAP_QosFlowSetupRequestItem *)
QosFlowSetupRequestList->list.array[l];
ogs_assert(QosFlowSetupRequestItem);
sess->qfi =
QosFlowSetupRequestItem->qosFlowIdentifier;
}
break;
case NGAP_ProtocolIE_ID_id_UL_NGU_UP_TNLInformation:
UPTransportLayerInformation =
&ie2->value.choice.UPTransportLayerInformation;
@ -231,6 +247,7 @@ void testngap_handle_pdu_session_resource_setup_request(
&sess->upf_n3_ip);
ogs_asn_OCTET_STRING_to_uint32(
&gTPTunnel->gTP_TEID, &sess->upf_n3_teid);
break;
default:
break;
}