diff --git a/src/mme/mme_context.c b/src/mme/mme_context.c index 0e1707dc8d..a3cd3a8fb1 100644 --- a/src/mme/mme_context.c +++ b/src/mme/mme_context.c @@ -52,6 +52,7 @@ status_t mme_context_init() gtp_node_init(); list_init(&self.sgw_list); + list_init(&self.pgw_list); index_init(&mme_enb_pool, MAX_NUM_OF_ENB); index_init(&mme_ue_pool, MAX_POOL_OF_UE); @@ -106,6 +107,7 @@ status_t mme_context_final() index_final(&mme_enb_pool); gtp_remove_all_nodes(&self.sgw_list); + gtp_remove_all_nodes(&self.pgw_list); gtp_node_final(); sock_remove_all_nodes(&self.gtpc4_list); @@ -128,7 +130,6 @@ static status_t mme_context_prepare() self.relative_capacity = 0xff; self.gtpc_port = GTPV2_C_UDP_PORT; - self.s5c_port = GTPV2_C_UDP_PORT; return CORE_OK; } @@ -164,6 +165,14 @@ static status_t mme_context_validation() } self.sgw = list_first(&self.sgw_list); + if (list_first(&self.pgw_list) == NULL) + { + d_error("No pgw.gtpc in '%s'", + context_self()->config.path); + return CORE_ERROR; + } + self.pgw = list_first(&self.pgw_list); + if (self.max_num_of_served_gummei == 0) { d_error("No mme.gummei in '%s'", @@ -328,7 +337,7 @@ status_t mme_context_parse_config() sock_node_t *node = NULL; int family = AF_UNSPEC; const char *hostname = NULL; - c_uint16_t port = GTPV2_C_UDP_PORT; + c_uint16_t port = self.gtpc_port; if (yaml_iter_type(>pc_array) == YAML_MAPPING_NODE) { @@ -858,7 +867,7 @@ status_t mme_context_parse_config() gtp_node_t *sgw = NULL; int family = AF_UNSPEC; const char *hostname = NULL; - c_uint16_t port = GTPV2_C_UDP_PORT; + c_uint16_t port = self.gtpc_port; if (yaml_iter_type(>pc_array) == YAML_MAPPING_NODE) { @@ -955,13 +964,10 @@ status_t mme_context_parse_config() yaml_iter_recurse(&mme_iter, >pc_array); do { -#if 0 - mme_pgw_t *pgw = NULL; -#endif + gtp_node_t *pgw = NULL; int family = AF_UNSPEC; const char *hostname = NULL; - c_uint16_t port = GTPV2_C_UDP_PORT; - const char *apn = NULL; + c_uint16_t port = self.gtpc_port; if (yaml_iter_type(>pc_array) == YAML_MAPPING_NODE) { @@ -1005,35 +1011,42 @@ status_t mme_context_parse_config() !strcmp(gtpc_key, "name")) { hostname = yaml_iter_value(>pc_iter); -#if 1 - if (hostname) - self.s5c_addr = inet_addr(hostname); -#endif } else if (!strcmp(gtpc_key, "port")) { const char *v = yaml_iter_value(>pc_iter); - if (v) - { - port = atoi(v); - self.gtpc_port = port; - } - } - else if (!strcmp(gtpc_key, "apn")) - { - apn = yaml_iter_value(>pc_iter); - printf("apn = [%s]\n", apn); + if (v) port = atoi(v); } else d_warn("unknown key `%s`", gtpc_key); } -#if 0 - pgw = mme_pgw_add(); + pgw = gtp_add_node(&self.pgw_list, + family, hostname, port); d_assert(pgw, return CORE_ERROR,); -#endif } while(yaml_iter_type(>pc_array) == YAML_SEQUENCE_NODE); + + if (context_self()->parameter.no_ipv4 == 1) + { + rv = gtp_filter_node(&self.pgw_list, AF_INET6); + d_assert(rv == CORE_OK, return CORE_ERROR,); + } + if (context_self()->parameter.no_ipv6 == 1) + { + rv = gtp_filter_node(&self.pgw_list, AF_INET); + d_assert(rv == CORE_OK, return CORE_ERROR,); + } + if (context_self()->parameter.prefer_ipv4 == 1) + { + rv = gtp_sort_node(&self.pgw_list, AF_INET); + d_assert(rv == CORE_OK, return CORE_ERROR,); + } + else + { + rv = gtp_sort_node(&self.pgw_list, AF_INET6); + d_assert(rv == CORE_OK, return CORE_ERROR,); + } } } } diff --git a/src/mme/mme_context.h b/src/mme/mme_context.h index 1dc6807129..f22821e2a7 100644 --- a/src/mme/mme_context.h +++ b/src/mme/mme_context.h @@ -66,8 +66,8 @@ typedef struct _mme_context_t { list_t sgw_list; /* SGW GTPC Client List */ gtp_node_t *sgw; /* Iterator for SGW round-robin */ - c_uint32_t s5c_addr; /* PGW S5C remote address */ - c_uint16_t s5c_port; /* PGW S5C remote port */ + list_t pgw_list; /* PGW GTPC Client List */ + gtp_node_t *pgw; /* First Node Selected */ msgq_id queue_id; /* Queue for processing MME control plane */ tm_service_t tm_service; /* Timer Service */ @@ -373,9 +373,6 @@ typedef struct _mme_sess_t { #define MME_UE_HAVE_APN(__mME) \ ((__mME) && (mme_sess_first(__mME)) && \ ((mme_sess_first(__mME))->pdn)) -#define MME_GET_PGW_IPV4_ADDR(__sESS) \ - (((__sESS) && ((__sESS)->pdn) && (((__sESS)->pdn)->pgw.ipv4_addr)) ? \ - (((__sESS)->pdn)->pgw.ipv4_addr) : (mme_self()->s5c_addr)) pdn_t *pdn; /* Save Protocol Configuration Options from UE */ diff --git a/src/mme/mme_s11_build.c b/src/mme/mme_s11_build.c index a132652610..3461449474 100644 --- a/src/mme/mme_s11_build.c +++ b/src/mme/mme_s11_build.c @@ -5,6 +5,7 @@ #include "gtp_types.h" #include "gtp_conv.h" #include "gtp_message.h" +#include "gtp_node.h" #include "types.h" #include "mme_context.h" @@ -29,15 +30,12 @@ status_t mme_s11_build_create_session_request( char bearer_qos_buf[GTP_BEARER_QOS_LEN]; gtp_ue_timezone_t ue_timezone; c_int8_t apn[MAX_APN_LEN]; - c_uint32_t pgw_ipv4_addr = 0; d_assert(sess, return CORE_ERROR, "Null param"); pdn = sess->pdn; d_assert(pdn, return CORE_ERROR, "Null param"); bearer = mme_default_bearer_in_sess(sess); d_assert(bearer, return CORE_ERROR, "Null param"); - pgw_ipv4_addr = MME_GET_PGW_IPV4_ADDR(sess); - d_assert(pgw_ipv4_addr, return CORE_ERROR, "Null param"); mme_ue = sess->mme_ue; d_assert(mme_ue, return CORE_ERROR, "Null param"); @@ -101,12 +99,40 @@ status_t mme_s11_build_create_session_request( req->sender_f_teid_for_control_plane.data = &mme_s11_teid; memset(&pgw_s5c_teid, 0, sizeof(gtp_f_teid_t)); - pgw_s5c_teid.ipv4 = 1; pgw_s5c_teid.interface_type = GTP_F_TEID_S5_S8_PGW_GTP_C; - pgw_s5c_teid.ipv4_addr = pgw_ipv4_addr; + if (pdn->pgw.ipv4_addr) + { + pgw_s5c_teid.ipv4 = 1; + pgw_s5c_teid.ipv4_addr = pdn->pgw.ipv4_addr; + } + else + { + c_sockaddr_t *s5c_addr = NULL; + + d_assert(mme_self()->pgw, return CORE_ERROR,); + s5c_addr = mme_self()->pgw->sa_list; + d_assert(s5c_addr, return CORE_ERROR,); + + if (s5c_addr->c_sa_family == AF_INET) + { + pgw_s5c_teid.ipv4 = 1; + pgw_s5c_teid.ipv4_addr = s5c_addr->sin.sin_addr.s_addr; + req->pgw_s5_s8_address_for_control_plane_or_pmip.len = + GTP_F_TEID_IPV4_LEN; + } + else if (s5c_addr->c_sa_family == AF_INET6) + { + pgw_s5c_teid.ipv6 = 1; + memcpy(pgw_s5c_teid.ipv6_addr, s5c_addr->sin6.sin6_addr.s6_addr, + sizeof(pgw_s5c_teid.ipv6_addr)); + req->pgw_s5_s8_address_for_control_plane_or_pmip.len = + GTP_F_TEID_IPV6_LEN; + } + else + d_assert(0, return CORE_ERROR,); + } req->pgw_s5_s8_address_for_control_plane_or_pmip.presence = 1; req->pgw_s5_s8_address_for_control_plane_or_pmip.data = &pgw_s5c_teid; - req->pgw_s5_s8_address_for_control_plane_or_pmip.len = GTP_F_TEID_IPV4_LEN; req->access_point_name.presence = 1; req->access_point_name.len = apn_build(apn, pdn->apn, strlen(pdn->apn));