diff --git a/src/mme/mme_context.c b/src/mme/mme_context.c index d9a1add1b8..831b6c946d 100644 --- a/src/mme/mme_context.c +++ b/src/mme/mme_context.c @@ -13,6 +13,7 @@ #include "s1ap_message.h" #include "gtp_xact.h" #include "gtp_node.h" +#include "gtp_path.h" #include "fd_lib.h" #include "context.h" @@ -972,6 +973,9 @@ status_t mme_context_parse_config() context_self()->parameter.prefer_ipv4); d_assert(rv == CORE_OK, return CORE_ERROR,); + rv = gtp_client(sgw); + d_assert(rv == CORE_OK, return CORE_ERROR,); + core_freeaddrinfo(list); } while(yaml_iter_type(>pc_array) == YAML_SEQUENCE_NODE); diff --git a/src/mme/mme_gtp_path.c b/src/mme/mme_gtp_path.c index 26059a7bf0..3d27396d7c 100644 --- a/src/mme/mme_gtp_path.c +++ b/src/mme/mme_gtp_path.c @@ -42,10 +42,11 @@ static int _gtpv2_c_recv_cb(sock_id sock, void *data) return 0; } -static status_t mme_gtp_server() +status_t mme_gtp_open() { status_t rv; sock_node_t *snode; + gtp_node_t *gnode; for (snode = list_first(&mme_self()->gtpc_list); snode; snode = list_next(snode)) @@ -92,25 +93,6 @@ static status_t mme_gtp_server() d_assert(mme_self()->gtpc_addr || mme_self()->gtpc_addr6, return CORE_ERROR, "No GTP Server"); - return CORE_OK; -} - -static status_t mme_gtp_client() -{ - status_t rv; - gtp_node_t *gnode = NULL; - - for (gnode = list_first(&mme_self()->sgw_list); - gnode; gnode = list_next(gnode)) - { - rv = gtp_client(gnode); - if (rv != CORE_OK) - { - d_error("Can't connect GTP-C Path to SGW"); - return rv; - } - } - mme_self()->sgw = list_first(&mme_self()->sgw_list); d_assert(mme_self()->sgw, return CORE_ERROR,); @@ -150,19 +132,6 @@ static status_t mme_gtp_client() return CORE_OK; } -status_t mme_gtp_open() -{ - status_t rv; - - rv = mme_gtp_server(); - if (rv != CORE_OK) return CORE_ERROR; - - rv = mme_gtp_client(); - if (rv != CORE_OK) return CORE_ERROR; - - return CORE_OK; -} - status_t mme_gtp_close() { sock_node_t *snode; diff --git a/src/mme/mme_s11_build.c b/src/mme/mme_s11_build.c index 9fc36cd281..92e3512050 100644 --- a/src/mme/mme_s11_build.c +++ b/src/mme/mme_s11_build.c @@ -71,6 +71,7 @@ status_t mme_s11_build_create_session_request( mme_s11_teid.teid = htonl(mme_ue->mme_s11_teid); rv = gtp_sockaddr_to_f_teid( mme_ue->mme_s11_ipv4, mme_ue->mme_s11_ipv6, &mme_s11_teid, &len); + d_assert(rv == CORE_OK, return CORE_ERROR,); req->sender_f_teid_for_control_plane.presence = 1; req->sender_f_teid_for_control_plane.data = &mme_s11_teid; req->sender_f_teid_for_control_plane.len = len; @@ -92,6 +93,7 @@ status_t mme_s11_build_create_session_request( { rv = gtp_sockaddr_to_f_teid( mme_self()->pgw_addr, mme_self()->pgw_addr6, &pgw_s5c_teid, &len); + d_assert(rv == CORE_OK, 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 = len; diff --git a/src/sgw/sgw_context.c b/src/sgw/sgw_context.c index 72dcaa7603..e2efe7257d 100644 --- a/src/sgw/sgw_context.c +++ b/src/sgw/sgw_context.c @@ -35,6 +35,9 @@ status_t sgw_context_init() memset(&self, 0, sizeof(sgw_context_t)); + list_init(&self.gtpc_list); + list_init(&self.gtpc_list6); + gtp_node_init(); list_init(&self.mme_list); list_init(&self.pgw_list); @@ -70,6 +73,9 @@ status_t sgw_context_final() gtp_remove_all_nodes(&self.pgw_list); gtp_node_final(); + sock_remove_all_nodes(&self.gtpc_list); + sock_remove_all_nodes(&self.gtpc_list6); + context_initialized = 0; return CORE_OK; @@ -90,9 +96,10 @@ static status_t sgw_context_prepare() static status_t sgw_context_validation() { - if (self.gtpc_addr == 0) + if (list_first(&self.gtpc_list) == NULL && + list_first(&self.gtpc_list6) == NULL) { - d_error("No sgw.gtpc in '%s'", + d_error("No mme.gtpc in '%s'", context_self()->config.path); return CORE_ERROR; } @@ -132,6 +139,7 @@ status_t sgw_context_parse_config() { const char *sgw_key = yaml_iter_key(&sgw_iter); d_assert(sgw_key, return CORE_ERROR,); +#if 0 if (!strcmp(sgw_key, "gtpc")) { yaml_iter_t gtpc_array, gtpc_iter; @@ -189,7 +197,7 @@ status_t sgw_context_parse_config() hostname = yaml_iter_value(>pc_iter); #if 1 if (hostname) - self.gtpc_addr = inet_addr(hostname); + self.old_gtpc_addr = inet_addr(hostname); #endif } else if (!strcmp(gtpc_key, "port")) @@ -212,6 +220,136 @@ status_t sgw_context_parse_config() } while(yaml_iter_type(>pc_array) == YAML_SEQUENCE_NODE); } +#else + if (!strcmp(sgw_key, "gtpc")) + { + yaml_iter_t gtpc_array, gtpc_iter; + yaml_iter_recurse(&sgw_iter, >pc_array); + do + { + int family = AF_UNSPEC; + int i, num = 0; +#define MAX_NUM_OF_HOSTNAME 16 + const char *hostname[MAX_NUM_OF_HOSTNAME]; + c_uint16_t port = self.gtpc_port; + c_sockaddr_t *list = NULL; + sock_node_t *node = NULL; + + if (yaml_iter_type(>pc_array) == YAML_MAPPING_NODE) + { + memcpy(>pc_iter, >pc_array, + sizeof(yaml_iter_t)); + } + else if (yaml_iter_type(>pc_array) == + YAML_SEQUENCE_NODE) + { + if (!yaml_iter_next(>pc_array)) + break; + yaml_iter_recurse(>pc_array, >pc_iter); + } + else if (yaml_iter_type(>pc_array) == + YAML_SCALAR_NODE) + { + break; + } + else + d_assert(0, return CORE_ERROR,); + + while(yaml_iter_next(>pc_iter)) + { + const char *gtpc_key = + yaml_iter_key(>pc_iter); + d_assert(gtpc_key, + return CORE_ERROR,); + if (!strcmp(gtpc_key, "family")) + { + const char *v = yaml_iter_value(>pc_iter); + if (v) family = atoi(v); + if (family != AF_UNSPEC && + family != AF_INET && family != AF_INET6) + { + d_warn("Ignore family(%d) : AF_UNSPEC(0), " + "AF_INET(2), AF_INET6(30) ", family); + family = AF_UNSPEC; + } + } + else if (!strcmp(gtpc_key, "addr") || + !strcmp(gtpc_key, "name")) + { + yaml_iter_t hostname_iter; + yaml_iter_recurse(>pc_iter, &hostname_iter); + d_assert(yaml_iter_type(&hostname_iter) != + YAML_MAPPING_NODE, return CORE_ERROR,); + + do + { + if (yaml_iter_type(&hostname_iter) == + YAML_SEQUENCE_NODE) + { + if (!yaml_iter_next(&hostname_iter)) + break; + } + + d_assert(num <= MAX_NUM_OF_HOSTNAME, + return CORE_ERROR,); + hostname[num++] = + yaml_iter_value(&hostname_iter); + } while( + yaml_iter_type(&hostname_iter) == + YAML_SEQUENCE_NODE); + } + else if (!strcmp(gtpc_key, "port")) + { + const char *v = yaml_iter_value(>pc_iter); + if (v) + { + port = atoi(v); + self.gtpc_port = port; + } + } + else + d_warn("unknown key `%s`", gtpc_key); + } + + list = NULL; + for (i = 0; i < num; i++) + { + rv = core_addaddrinfo(&list, + family, hostname[i], port, AI_PASSIVE); + d_assert(rv == CORE_OK, return CORE_ERROR,); + } + + if (context_self()->parameter.no_ipv4 == 0) + { + rv = sock_add_node(&self.gtpc_list, + &node, list, AF_INET); + d_assert(rv == CORE_OK, return CORE_ERROR,); + } + + if (context_self()->parameter.no_ipv6 == 0) + { + rv = sock_add_node(&self.gtpc_list, + &node, list, AF_INET6); + d_assert(rv == CORE_OK, return CORE_ERROR,); + } + + core_freeaddrinfo(list); + + } while(yaml_iter_type(>pc_array) == YAML_SEQUENCE_NODE); + + if (list_first(&self.gtpc_list) == NULL && + list_first(&self.gtpc_list6) == NULL) + { + rv = sock_probe_node( + context_self()->parameter.no_ipv4 ? + NULL : &self.gtpc_list, + context_self()->parameter.no_ipv6 ? + NULL : &self.gtpc_list6, + self.gtpc_port); + d_assert(rv == CORE_OK, return CORE_ERROR,); + } + } +#endif else if (!strcmp(sgw_key, "gtpu")) { yaml_iter_t gtpu_array, gtpu_iter; @@ -360,7 +498,8 @@ sgw_ue_t* sgw_ue_add( d_assert(sgw_ue, return NULL, "Null param"); sgw_ue->sgw_s11_teid = sgw_ue->index; - sgw_ue->sgw_s11_addr = sgw_self()->gtpc_addr; + sgw_ue->sgw_s11_ipv4 = sgw_self()->gtpc_addr; + sgw_ue->sgw_s11_ipv6 = sgw_self()->gtpc_addr6; /* Set IMSI */ sgw_ue->imsi_len = imsi_len; @@ -535,7 +674,8 @@ sgw_sess_t *sgw_sess_add( d_assert(sess, return NULL, "Null param"); sess->sgw_s5c_teid = SGW_S5C_INDEX_TO_TEID(sess->index); - sess->sgw_s5c_addr = sgw_self()->gtpc_addr; + sess->sgw_s5c_ipv4 = sgw_self()->gtpc_addr; + sess->sgw_s5c_ipv6 = sgw_self()->gtpc_addr6; /* Set APN */ core_cpystrn(sess->pdn.apn, apn, MAX_APN_LEN+1); diff --git a/src/sgw/sgw_context.h b/src/sgw/sgw_context.h index f4554827dd..708dec1c00 100644 --- a/src/sgw/sgw_context.h +++ b/src/sgw/sgw_context.h @@ -20,9 +20,12 @@ typedef struct _sgw_tunnel_t sgw_tunnel_t; typedef struct _gtp_node_t gtp_node_t; typedef struct _sgw_context_t { - c_uint32_t gtpc_addr; /* GTP-U local address */ - c_uint32_t gtpc_port; /* GTP-U local port */ - sock_id gtpc_sock; /* GTP-U local listen socket */ + c_uint32_t gtpc_port; /* Default GTPC port */ + + list_t gtpc_list; /* SGW GTPC IPv4 Server List */ + c_sockaddr_t *gtpc_addr; /* SGW GTPC IPv4 Address */ + list_t gtpc_list6; /* SGW GTPC IPv6 Server List */ + c_sockaddr_t *gtpc_addr6; /* SGW GTPC IPv6 Address */ c_uint32_t gtpu_addr; /* GTP-U local address */ c_uint32_t gtpu_port; /* GTP-U local port */ @@ -44,7 +47,8 @@ typedef struct _sgw_ue_t { /* IMPORTANT! * SGW-S11-F-TEID is same with an index */ c_uint32_t sgw_s11_teid; - c_uint32_t sgw_s11_addr; + c_sockaddr_t *sgw_s11_ipv4; /* SGW S11 IPv4 Address */ + c_sockaddr_t *sgw_s11_ipv6; /* SGW S11 IPv6 Address */ c_uint32_t mme_s11_teid; /* MME-S11-F-TEID */ c_uint32_t mme_s11_addr; /* MME-S11-F-TEID IPv4 Address */ @@ -85,7 +89,8 @@ typedef struct _sgw_sess_t { #define SGW_S5C_TEID_TO_INDEX(__iNDEX) (__iNDEX & ~0x80000000) #define SGW_S5C_INDEX_TO_TEID(__iNDEX) (__iNDEX | 0x80000000) c_uint32_t sgw_s5c_teid; - c_uint32_t sgw_s5c_addr; + c_sockaddr_t *sgw_s5c_ipv4; /* SGW S5C IPv4 Address */ + c_sockaddr_t *sgw_s5c_ipv6; /* SGW S5C IPv6 Address */ c_uint32_t pgw_s5c_teid; /* PGW-S5C-F-TEID */ c_uint32_t pgw_s5c_addr; /* PGW-S5C-F-TEID IPv4 Address */ diff --git a/src/sgw/sgw_gtp_path.c b/src/sgw/sgw_gtp_path.c index 4347fd5e7c..3ab0c8e4a4 100644 --- a/src/sgw/sgw_gtp_path.c +++ b/src/sgw/sgw_gtp_path.c @@ -228,15 +228,53 @@ static int _gtpv1_u_recv_cb(sock_id sock, void *data) status_t sgw_gtp_open() { status_t rv; + sock_node_t *snode; - rv = gtp_listen(&sgw_self()->gtpc_sock, _gtpv2_c_recv_cb, - sgw_self()->gtpc_addr, sgw_self()->gtpc_port, NULL); - if (rv != CORE_OK) + for (snode = list_first(&sgw_self()->gtpc_list); + snode; snode = list_next(snode)) { - d_error("Can't establish GTP-C Path for MME/PGW"); - return rv; + rv = gtp_server(snode, _gtpv2_c_recv_cb); + if (rv != CORE_OK) + { + d_error("Can't establish GTP-C Path for SGW"); + return rv; + } } + for (snode = list_first(&sgw_self()->gtpc_list); + snode; snode = list_next(snode)) + { + sgw_self()->gtpc_addr = sock_local_addr(snode->sock); + if (sgw_self()->gtpc_addr) + { + break; + } + } + + for (snode = list_first(&sgw_self()->gtpc_list6); + snode; snode = list_next(snode)) + { + rv = gtp_server(snode, _gtpv2_c_recv_cb); + if (rv != CORE_OK) + { + d_error("Can't establish GTP-C Path for SGW"); + return rv; + } + } + + for (snode = list_first(&sgw_self()->gtpc_list6); + snode; snode = list_next(snode)) + { + sgw_self()->gtpc_addr6 = sock_local_addr(snode->sock); + if (sgw_self()->gtpc_addr6) + { + break; + } + } + + d_assert(sgw_self()->gtpc_addr || sgw_self()->gtpc_addr6, + return CORE_ERROR, "No GTP Server"); + rv = gtp_listen(&sgw_self()->gtpu_sock, _gtpv1_u_recv_cb, sgw_self()->gtpu_addr, sgw_self()->gtpu_port, NULL); if (rv != CORE_OK) @@ -252,11 +290,18 @@ status_t sgw_gtp_close() { status_t rv; - rv = gtp_close(sgw_self()->gtpc_sock); - if (rv != CORE_OK) + sock_node_t *snode; + + for (snode = list_first(&sgw_self()->gtpc_list); + snode; snode = list_next(snode)) { - d_error("Can't close GTP-C Path for MME/PGW"); - return rv; + sock_delete(snode->sock); + } + + for (snode = list_first(&sgw_self()->gtpc_list6); + snode; snode = list_next(snode)) + { + sock_delete(snode->sock); } rv = gtp_close(sgw_self()->gtpu_sock); diff --git a/src/sgw/sgw_s11_handler.c b/src/sgw/sgw_s11_handler.c index b3830f8451..e2e38a9c9b 100644 --- a/src/sgw/sgw_s11_handler.c +++ b/src/sgw/sgw_s11_handler.c @@ -23,6 +23,7 @@ void sgw_s11_handle_create_session_request(gtp_xact_t *s11_xact, pkbuf_t *pkbuf = NULL; gtp_f_teid_t *mme_s11_teid = NULL; gtp_f_teid_t *pgw_s5c_teid = NULL; + int len = 0; gtp_node_t *pgw = NULL; gtp_f_teid_t sgw_s5c_teid, sgw_s5u_teid; gtp_uli_t uli; @@ -88,13 +89,14 @@ void sgw_s11_handle_create_session_request(gtp_xact_t *s11_xact, /* Send Control Plane(DL) : SGW-S5C */ memset(&sgw_s5c_teid, 0, sizeof(gtp_f_teid_t)); - sgw_s5c_teid.teid = htonl(sess->sgw_s5c_teid); - sgw_s5c_teid.ipv4 = 1; - sgw_s5c_teid.ip.addr = sess->sgw_s5c_addr; sgw_s5c_teid.interface_type = GTP_F_TEID_S5_S8_SGW_GTP_C; + sgw_s5c_teid.teid = htonl(sess->sgw_s5c_teid); + rv = gtp_sockaddr_to_f_teid( + sess->sgw_s5c_ipv4, sess->sgw_s5c_ipv6, &sgw_s5c_teid, &len); + d_assert(rv == CORE_OK, return,); req->sender_f_teid_for_control_plane.presence = 1; req->sender_f_teid_for_control_plane.data = &sgw_s5c_teid; - req->sender_f_teid_for_control_plane.len = GTP_F_TEID_IPV4_LEN; + req->sender_f_teid_for_control_plane.len = len; pgw_s5c_teid = req->pgw_s5_s8_address_for_control_plane_or_pmip.data; d_assert(pgw_s5c_teid, return, "Null param"); diff --git a/src/sgw/sgw_s5c_handler.c b/src/sgw/sgw_s5c_handler.c index 0458025f53..780c073411 100644 --- a/src/sgw/sgw_s5c_handler.c +++ b/src/sgw/sgw_s5c_handler.c @@ -3,6 +3,7 @@ #include "core_debug.h" #include "core_lib.h" +#include "gtp_conv.h" #include "gtp_types.h" #include "sgw_event.h" @@ -25,6 +26,7 @@ void sgw_s5c_handle_create_session_response(gtp_xact_t *s5c_xact, gtp_f_teid_t sgw_s11_teid; gtp_f_teid_t *pgw_s5u_teid = NULL; gtp_f_teid_t sgw_s1u_teid; + int len; d_assert(sess, return, "Null param"); sgw_ue = sess->sgw_ue; @@ -84,13 +86,14 @@ void sgw_s5c_handle_create_session_response(gtp_xact_t *s5c_xact, /* Send Control Plane(UL) : SGW-S11 */ memset(&sgw_s11_teid, 0, sizeof(gtp_f_teid_t)); - sgw_s11_teid.ipv4 = 1; sgw_s11_teid.interface_type = GTP_F_TEID_S11_S4_SGW_GTP_C; - sgw_s11_teid.ip.addr = sgw_ue->sgw_s11_addr; sgw_s11_teid.teid = htonl(sgw_ue->sgw_s11_teid); + rv = gtp_sockaddr_to_f_teid( + sgw_ue->sgw_s11_ipv4, sgw_ue->sgw_s11_ipv6, &sgw_s11_teid, &len); + d_assert(rv == CORE_OK, return, ); rsp->sender_f_teid_for_control_plane.presence = 1; rsp->sender_f_teid_for_control_plane.data = &sgw_s11_teid; - rsp->sender_f_teid_for_control_plane.len = GTP_F_TEID_IPV4_LEN; + rsp->sender_f_teid_for_control_plane.len = len; /* Send Data Plane(UL) : SGW-S1U */ memset(&sgw_s1u_teid, 0, sizeof(gtp_f_teid_t));