diff --git a/lib/core/include/core_network.h b/lib/core/include/core_network.h index 185e81e74..4a1960473 100644 --- a/lib/core/include/core_network.h +++ b/lib/core/include/core_network.h @@ -207,8 +207,7 @@ CORE_DECLARE(int) core_sctp_recvmsg(sock_id id, void *msg, size_t len, */ CORE_DECLARE(status_t) tun_open(sock_id *new, char *ifname, int is_tap); -CORE_DECLARE(status_t) tun_set_ip(sock_id id, - const char *ipstr, const char *mask_or_numbits); +CORE_DECLARE(status_t) tun_set_ip(sock_id id, ipsubnet_t *gw, ipsubnet_t *sub); /* * Send/Recv diff --git a/lib/core/src/unix/tun.c b/lib/core/src/unix/tun.c index 44fcf1784..f4dfb1e86 100644 --- a/lib/core/src/unix/tun.c +++ b/lib/core/src/unix/tun.c @@ -342,32 +342,20 @@ status_t tun_set_ipv6(sock_id id, ipsubnet_t *ipaddr, ipsubnet_t *ipsub) return CORE_OK; } -status_t tun_set_ip(sock_id id, const char *ipstr, const char *mask_or_numbits) +status_t tun_set_ip(sock_id id, ipsubnet_t *gw, ipsubnet_t *sub) { - ipsubnet_t ipaddr, ipsub; status_t rv; d_assert(id, return CORE_ERROR,); - d_assert(ipstr, return CORE_ERROR,); - d_assert(mask_or_numbits, return CORE_ERROR,); + d_assert(gw, return CORE_ERROR,); + d_assert(sub, return CORE_ERROR,); - rv = core_ipsubnet(&ipaddr, ipstr, NULL); - d_assert(rv == CORE_OK, return CORE_ERROR,); - - rv = core_ipsubnet(&ipsub, ipstr, mask_or_numbits); - d_assert(rv == CORE_OK, return CORE_ERROR,); - - if (ipsub.family == AF_INET) - { - rv = tun_set_ipv4(id, &ipaddr, &ipsub); - } - else if (ipsub.family == AF_INET6) - { + if (gw->family == AF_INET) + rv = tun_set_ipv4(id, gw, sub); + else if (gw->family == AF_INET6) #if 0 - rv = tun_set_ipv6(id, &ipaddr, &ipsub); + rv = tun_set_ipv6(id, gw, sub); #endif - return CORE_OK; - } else d_assert(0, return CORE_ERROR,); diff --git a/src/pgw/pgw_context.c b/src/pgw/pgw_context.c index c96d5a5b0..4f5a23794 100644 --- a/src/pgw/pgw_context.c +++ b/src/pgw/pgw_context.c @@ -22,27 +22,18 @@ static pgw_context_t self; +pool_declare(pgw_dev_pool, pgw_dev_t, MAX_NUM_OF_DEV); +pool_declare(pgw_subnet_pool, pgw_subnet_t, MAX_NUM_OF_SUBNET); + index_declare(pgw_sess_pool, pgw_sess_t, MAX_POOL_OF_SESS); index_declare(pgw_bearer_pool, pgw_bearer_t, MAX_POOL_OF_BEARER); pool_declare(pgw_pf_pool, pgw_pf_t, MAX_POOL_OF_PF); -typedef struct _ue_pool_t { - int head, tail; - int size, avail; - mutex_id mut; - pgw_ue_ip_t *free[MAX_POOL_OF_SESS], pool[MAX_POOL_OF_SESS]; -} ue_pool_t; - -#define INVALID_POOL_INDEX MAX_NUM_OF_UE_POOL -static ue_pool_t ue_ip_pool[MAX_NUM_OF_UE_POOL]; - static int context_initiaized = 0; status_t pgw_context_init() { - int i; - d_assert(context_initiaized == 0, return CORE_ERROR, "PGW context already has been initialized"); @@ -57,14 +48,16 @@ status_t pgw_context_init() list_init(&self.sgw_s5c_list); list_init(&self.sgw_s5u_list); + list_init(&self.dev_list); + pool_init(&pgw_dev_pool, MAX_NUM_OF_DEV); + list_init(&self.subnet_list); + pool_init(&pgw_subnet_pool, MAX_NUM_OF_SUBNET); + index_init(&pgw_sess_pool, MAX_POOL_OF_SESS); index_init(&pgw_bearer_pool, MAX_POOL_OF_BEARER); pool_init(&pgw_pf_pool, MAX_POOL_OF_PF); - for (i = 0; i < MAX_NUM_OF_UE_POOL; i++) - pool_init(&ue_ip_pool[i], MAX_POOL_OF_UE); - self.sess_hash = hash_make(); context_initiaized = 1; @@ -74,8 +67,6 @@ status_t pgw_context_init() status_t pgw_context_final() { - int i; - d_assert(context_initiaized == 1, return CORE_ERROR, "PGW context already has been finalized"); @@ -90,23 +81,15 @@ status_t pgw_context_final() d_trace(3, "%d not freed in pgw_sess_pool[%d] in PGW-Context\n", index_used(&pgw_sess_pool), index_size(&pgw_sess_pool)); - pool_final(&pgw_pf_pool); - - for (i = 0; i < MAX_NUM_OF_UE_POOL; i++) - { - if (pool_used(&ue_ip_pool[i])) - { - d_warn("[%d] %d not freed in ue_ip_pool[%d] in PGW-Context", - i, pool_used(&ue_ip_pool[i]), index_size(&ue_ip_pool[i])); - } - d_trace(3, "[%d] %d not freed in ue_ip_pool[%d] in PGW-Context\n", - i, pool_used(&ue_ip_pool[i]), index_size(&ue_ip_pool[i])); - - pool_final(&ue_ip_pool[i]); - } + pgw_dev_remove_all(); + pgw_subnet_remove_all(); index_final(&pgw_bearer_pool); index_final(&pgw_sess_pool); + pool_final(&pgw_pf_pool); + + pool_final(&pgw_dev_pool); + pool_final(&pgw_subnet_pool); gtp_remove_all_nodes(&self.sgw_s5c_list); gtp_remove_all_nodes(&self.sgw_s5u_list); @@ -499,12 +482,12 @@ status_t pgw_context_parse_config() yaml_iter_recurse(&pgw_iter, &ue_pool_array); do { + pgw_subnet_t *subnet = NULL; const char *ipstr = NULL; const char *mask_or_numbits = NULL; const char *apn = NULL; + const char *dev = self.tun_ifname; - d_assert(self.num_of_ue_pool <= - MAX_NUM_OF_UE_POOL, return CORE_ERROR,); if (yaml_iter_type(&ue_pool_array) == YAML_MAPPING_NODE) { @@ -550,17 +533,19 @@ status_t pgw_context_parse_config() { apn = yaml_iter_value(&ue_pool_iter); } + else if (!strcmp(ue_pool_key, "dev")) + { + dev = yaml_iter_value(&ue_pool_iter); + } else d_warn("unknown key `%s`", ue_pool_key); } if (ipstr && mask_or_numbits) { - self.ue_pool[self.num_of_ue_pool].ipstr = ipstr; - self.ue_pool[self.num_of_ue_pool].mask_or_numbits = - mask_or_numbits; - self.ue_pool[self.num_of_ue_pool].apn = apn; - self.num_of_ue_pool++; + subnet = pgw_subnet_add( + ipstr, mask_or_numbits, apn, dev); + d_assert(subnet, return CORE_ERROR,); } else { @@ -1131,54 +1116,41 @@ pgw_pf_t* pgw_pf_next(pgw_pf_t *pf) status_t pgw_ue_pool_generate() { - status_t rv; - int i, j; + int j; + pgw_subnet_t *subnet = NULL; - for (i = 0; i < self.num_of_ue_pool; i++) + for (subnet = pgw_subnet_first(); subnet; subnet = pgw_subnet_next(subnet)) { int index = 0; - ipsubnet_t ipaddr, ipsub; - c_uint32_t prefixlen; c_uint32_t mask_count; c_uint32_t broadcast[4]; - rv = core_ipsubnet(&ipaddr, self.ue_pool[i].ipstr, NULL); - d_assert(rv == CORE_OK, return CORE_ERROR,); - - rv = core_ipsubnet(&ipsub, - self.ue_pool[i].ipstr, self.ue_pool[i].mask_or_numbits); - d_assert(rv == CORE_OK, return CORE_ERROR,); - - d_assert(self.ue_pool[i].mask_or_numbits, return CORE_ERROR,); - prefixlen = atoi(self.ue_pool[i].mask_or_numbits); - if (ipsub.family == AF_INET) + if (subnet->family == AF_INET) { - if (prefixlen == 32) + if (subnet->prefixlen == 32) mask_count = 1; - else if (prefixlen < 32) - mask_count = (0xffffffff >> prefixlen) + 1; + else if (subnet->prefixlen < 32) + mask_count = (0xffffffff >> subnet->prefixlen) + 1; else d_assert(0, return CORE_ERROR,); } - else if (ipsub.family == AF_INET6) + else if (subnet->family == AF_INET6) { - if (prefixlen == 128) + if (subnet->prefixlen == 128) mask_count = 1; - else if (prefixlen > 96 && prefixlen < 128) - mask_count = (0xffffffff >> (prefixlen - 96)) + 1; - else if (prefixlen <= 96) + else if (subnet->prefixlen > 96 && subnet->prefixlen < 128) + mask_count = (0xffffffff >> (subnet->prefixlen - 96)) + 1; + else if (subnet->prefixlen <= 96) mask_count = 0xffffffff; else d_assert(0, return CORE_ERROR,); } else d_assert(0, return CORE_ERROR,); - - self.ue_pool[i].family = ipsub.family; for (j = 0; j < 4; j++) { - broadcast[j] = ipsub.sub[j] + ~ipsub.mask[j]; + broadcast[j] = subnet->sub.sub[j] + ~subnet->sub.mask[j]; } for (j = 0; j < mask_count && index < MAX_POOL_OF_SESS; j++) @@ -1187,126 +1159,276 @@ status_t pgw_ue_pool_generate() int maxbytes = 0; int lastindex = 0; - ue_ip = &ue_ip_pool[i].pool[index]; + ue_ip = &subnet->pool.pool[index]; d_assert(ue_ip, return CORE_ERROR,); memset(ue_ip, 0, sizeof *ue_ip); - if (ipsub.family == AF_INET) + if (subnet->family == AF_INET) { maxbytes = 4; lastindex = 0; } - else if (ipsub.family == AF_INET6) + else if (subnet->family == AF_INET6) { maxbytes = 16; lastindex = 3; } - memcpy(ue_ip->addr, ipsub.sub, maxbytes); + memcpy(ue_ip->addr, subnet->sub.sub, maxbytes); ue_ip->addr[lastindex] += htonl(j); + ue_ip->subnet = subnet; /* Exclude Network Address */ - if (memcmp(ue_ip->addr, ipsub.sub, maxbytes) == 0) continue; + if (memcmp(ue_ip->addr, subnet->sub.sub, maxbytes) == 0) continue; /* Exclude Broadcast Address */ if (memcmp(ue_ip->addr, broadcast, maxbytes) == 0) continue; /* Exclude TUN IP Address */ - if (memcmp(ue_ip->addr, ipaddr.sub, maxbytes) == 0) continue; + if (memcmp(ue_ip->addr, subnet->gw.sub, maxbytes) == 0) continue; index++; } - ue_ip_pool[i].size = ue_ip_pool[i].avail = index; + subnet->pool.size = subnet->pool.avail = index; } return CORE_OK; } -static c_uint8_t find_ue_pool_index(int family, const char *apn) +static pgw_subnet_t *find_subnet(int family, const char *apn) { - int i; - c_uint8_t pool_index = INVALID_POOL_INDEX; + pgw_subnet_t *subnet = NULL; - d_assert(apn, return INVALID_POOL_INDEX,); - d_assert(family == AF_INET || family == AF_INET6, - return INVALID_POOL_INDEX,); + d_assert(apn, return NULL,); + d_assert(family == AF_INET || family == AF_INET6, return NULL,); - for (i = 0; i < self.num_of_ue_pool; i++) + for (subnet = pgw_subnet_first(); subnet; subnet = pgw_subnet_next(subnet)) { - if (self.ue_pool[i].apn) + if (strlen(subnet->apn)) { - if (self.ue_pool[i].family == family && - strcmp(self.ue_pool[i].apn, apn) == 0 && - pool_avail(&ue_ip_pool[i])) + if (subnet->family == family && strcmp(subnet->apn, apn) == 0 && + pool_avail(&subnet->pool)) { - pool_index = i; - break; + return subnet; } } } - if (pool_index == INVALID_POOL_INDEX) + for (subnet = pgw_subnet_first(); subnet; subnet = pgw_subnet_next(subnet)) { - for (i = 0; i < self.num_of_ue_pool; i++) + if (strlen(subnet->apn) == 0) { - if (self.ue_pool[i].apn == NULL) + if (subnet->family == family && + pool_avail(&subnet->pool)) { - if (self.ue_pool[i].family == family && - pool_avail(&ue_ip_pool[i])) - { - pool_index = i; - break; - } + return subnet; } } } - if (pool_index == INVALID_POOL_INDEX) - { + if (subnet == NULL) d_error("CHECK CONFIGURATION: Cannot find UE Pool"); - return INVALID_POOL_INDEX; - } - return pool_index; + return subnet; } pgw_ue_ip_t *pgw_ue_ip_alloc(int family, const char *apn) { - c_uint8_t pool_index = INVALID_POOL_INDEX; + pgw_subnet_t *subnet = NULL; pgw_ue_ip_t *ue_ip = NULL; d_assert(apn, return NULL,); - pool_index = find_ue_pool_index(family, apn); - d_assert(pool_index < MAX_NUM_OF_UE_POOL, return NULL,); + subnet = find_subnet(family, apn); + d_assert(subnet, return NULL,); - pool_alloc_node(&ue_ip_pool[pool_index], &ue_ip); + pool_alloc_node(&subnet->pool, &ue_ip); d_assert(ue_ip, return NULL,); - ue_ip->index = pool_index; return ue_ip; } status_t pgw_ue_ip_free(pgw_ue_ip_t *ue_ip) { - c_uint8_t pool_index; + pgw_subnet_t *subnet = NULL; d_assert(ue_ip, return CORE_ERROR,); - pool_index = ue_ip->index; + subnet = ue_ip->subnet; - d_assert(pool_index < MAX_NUM_OF_UE_POOL, return CORE_ERROR,); - pool_free_node(&ue_ip_pool[pool_index], ue_ip); + d_assert(subnet, return CORE_ERROR,); + pool_free_node(&subnet->pool, ue_ip); return CORE_OK; } c_uint8_t pgw_ue_ip_prefixlen(pgw_ue_ip_t *ue_ip) { - d_assert(ue_ip, return CORE_ERROR,); + pgw_subnet_t *subnet = NULL; - c_uint8_t index = ue_ip->index; - d_assert(index < MAX_NUM_OF_UE_POOL, return CORE_ERROR,); - d_assert(pgw_self()->ue_pool[index].mask_or_numbits, - return CORE_ERROR,); - return atoi(pgw_self()->ue_pool[index].mask_or_numbits); + d_assert(ue_ip, return -1,); + subnet = ue_ip->subnet; + d_assert(subnet, return -1,); + + return subnet->prefixlen; +} + +pgw_dev_t *pgw_dev_add(const char *ifname) +{ + pgw_dev_t *dev = NULL; + + d_assert(ifname, return NULL,); + + pool_alloc_node(&pgw_dev_pool, &dev); + d_assert(dev, return NULL,); + memset(dev, 0, sizeof *dev); + + strcpy(dev->ifname, ifname); + + list_append(&self.dev_list, dev); + + return dev; +} + +status_t pgw_dev_remove(pgw_dev_t *dev) +{ + d_assert(dev, return CORE_ERROR, "Null param"); + + list_remove(&self.dev_list, dev); + pool_free_node(&pgw_dev_pool, dev); + + return CORE_OK; +} + +status_t pgw_dev_remove_all() +{ + pgw_dev_t *dev = NULL, *next_dev = NULL; + + dev = pgw_dev_first(); + while (dev) + { + next_dev = pgw_dev_next(dev); + + pgw_dev_remove(dev); + + dev = next_dev; + } + + return CORE_OK; +} + +pgw_dev_t* pgw_dev_find_by_ifname(const char *ifname) +{ + pgw_dev_t *dev = NULL; + + d_assert(ifname, return NULL,); + + dev = pgw_dev_first(); + while (dev) + { + if (strcmp(dev->ifname, ifname) == 0) + return dev; + + dev = pgw_dev_next(dev); + } + + return CORE_OK; +} + +pgw_dev_t* pgw_dev_first() +{ + return list_first(&self.dev_list); +} + +pgw_dev_t* pgw_dev_next(pgw_dev_t *dev) +{ + return list_next(dev); +} + +pgw_subnet_t *pgw_subnet_add( + const char *ipstr, const char *mask_or_numbits, + const char *apn, const char *ifname) +{ + status_t rv; + pgw_dev_t *dev = NULL; + pgw_subnet_t *subnet = NULL; + + d_assert(ipstr, return NULL,); + d_assert(mask_or_numbits, return NULL,); + d_assert(ifname, return NULL,); + + dev = pgw_dev_find_by_ifname(ifname); + if (!dev) + dev = pgw_dev_add(ifname); + d_assert(dev, return NULL,); + + pool_alloc_node(&pgw_subnet_pool, &subnet); + d_assert(subnet, return NULL,); + memset(subnet, 0, sizeof *subnet); + + subnet->dev = dev; + + rv = core_ipsubnet(&subnet->gw, ipstr, NULL); + d_assert(rv == CORE_OK, return NULL,); + + rv = core_ipsubnet(&subnet->sub, ipstr, mask_or_numbits); + d_assert(rv == CORE_OK, return NULL,); + + if (apn) + strcpy(subnet->apn, apn); + + subnet->family = subnet->gw.family; + subnet->prefixlen = atoi(mask_or_numbits); + + pool_init(&subnet->pool, MAX_POOL_OF_UE); + + list_append(&self.subnet_list, subnet); + + return subnet; +} + +status_t pgw_subnet_remove(pgw_subnet_t *subnet) +{ + d_assert(subnet, return CORE_ERROR, "Null param"); + + list_remove(&self.subnet_list, subnet); + + if (pool_used(&subnet->pool)) + { + d_warn("%d not freed in ue_ip_pool[%d] in PGW-Context", + pool_used(&subnet->pool), pool_size(&subnet->pool)); + } + d_trace(3, "%d not freed in ue_ip_pool[%d] in PGW-Context\n", + pool_used(&subnet->pool), pool_size(&subnet->pool)); + pool_final(&subnet->pool); + + pool_free_node(&pgw_subnet_pool, subnet); + + return CORE_OK; +} + +status_t pgw_subnet_remove_all() +{ + pgw_subnet_t *subnet = NULL, *next_subnet = NULL; + + subnet = pgw_subnet_first(); + while (subnet) + { + next_subnet = pgw_subnet_next(subnet); + + pgw_subnet_remove(subnet); + + subnet = next_subnet; + } + + return CORE_OK; +} + +pgw_subnet_t* pgw_subnet_first() +{ + return list_first(&self.subnet_list); +} + +pgw_subnet_t* pgw_subnet_next(pgw_subnet_t *subnet) +{ + return list_next(subnet); } diff --git a/src/pgw/pgw_context.h b/src/pgw/pgw_context.h index 302478cef..7d88b2440 100644 --- a/src/pgw/pgw_context.h +++ b/src/pgw/pgw_context.h @@ -16,11 +16,15 @@ extern "C" { #endif /* __cplusplus */ +#define MAX_NUM_OF_DEV 16 +#define MAX_NUM_OF_SUBNET 16 + typedef struct _gtp_node_t gtp_node_t; typedef struct _pgw_context_t { - c_uint32_t gtpc_port; /* PGW GTP-C local port */ - c_uint32_t gtpu_port; /* PGW GTP-U local port */ + c_uint32_t gtpc_port; /* Default: PGW GTP-C local port */ + c_uint32_t gtpu_port; /* Default: PGW GTP-U local port */ + const char *tun_ifname; /* Default:: pgwtun */ list_t gtpc_list; /* PGW GTPC IPv4 Server List */ c_sockaddr_t *gtpc_addr; /* PGW GTPC IPv4 Address */ @@ -32,30 +36,17 @@ typedef struct _pgw_context_t { list_t gtpu_list6; /* PGW GTPU IPv6 Server List */ c_sockaddr_t *gtpu_addr6; /* PGW GTPU IPv6 Address */ + list_t dev_list; /* PGW Tun Device List */ + list_t subnet_list; /* PGW UE Subnet List */ + const char* fd_conf_path; /* PGW freeDiameter conf path */ msgq_id queue_id; /* Qsesssess for processing PGW control plane */ tm_service_t tm_service; /* Timer Service */ - sock_id tun_sock; /* PGW Tun Interace for UE */ - const char *tun_ifname; /* default : pgwtun */ -#define MAX_NUM_OF_UE_POOL 16 - struct { - const char *ipstr; /* IP : "172.16.0.1", "cafe::1", ... */ - const char *mask_or_numbits; /* MASK : "16, 64, ... */ - const char *apn; /* APN : "internet", "volte", .. */ - int family; /* AF_INET or AF_INET6 */ - } ue_pool[MAX_NUM_OF_UE_POOL]; - c_uint8_t num_of_ue_pool; - - struct { - c_uint32_t primary; - c_uint32_t secondary; - } old_dns; - #define MAX_NUM_OF_DNS 2 - const char *dns[2]; /* Primary/Secondanry */ - const char *dns6[2]; /* Primary/Secondanry */ + const char *dns[MAX_NUM_OF_DNS]; /* Primary/Secondanry */ + const char *dns6[MAX_NUM_OF_DNS]; /* Primary/Secondanry */ list_t sgw_s5c_list; /* SGW GTPC Node List */ list_t sgw_s5u_list; /* SGW GTPU Node List */ @@ -64,17 +55,44 @@ typedef struct _pgw_context_t { hash_t *sess_hash; /* hash table (IMSI+APN) */ } pgw_context_t; -typedef struct _pgw_ip_pool_t { - lnode_t node; /**< A node of list_t */ - - c_uint32_t ue_addr; -} pgw_ip_pool_t; - +typedef struct _pgw_subnet_t pgw_subnet_t; typedef struct _pgw_ue_ip_t { - c_uint8_t index; /* Pool index */ c_uint32_t addr[4]; + + /* Related Context */ + pgw_subnet_t *subnet; } pgw_ue_ip_t; +typedef struct _pgw_dev_t { + lnode_t node; + + c_int8_t ifname[IFNAMSIZ]; + sock_id sock; + + c_uint8_t link_local_addr[IPV6_LEN]; +} pgw_dev_t; + +typedef struct _pgw_subnet_t { + lnode_t node; + + ipsubnet_t sub; /* Subnet : cafe::0/64 */ + ipsubnet_t gw; /* Gateway : cafe::1 */ + c_int8_t apn[MAX_APN_LEN]; /* APN : "internet", "volte", .. */ + + int family; /* AF_INET or AF_INET6 */ + c_uint8_t prefixlen; /* prefixlen */ + + struct { + int head, tail; + int size, avail; + mutex_id mut; + pgw_ue_ip_t *free[MAX_POOL_OF_SESS], pool[MAX_POOL_OF_SESS]; + } pool; + + /* Related Context */ + pgw_dev_t *dev; +} pgw_subnet_t; + typedef struct _pgw_sess_t { lnode_t node; /**< A node of list_t */ index_t index; /**< An index of this node */ @@ -223,6 +241,21 @@ CORE_DECLARE(pgw_ue_ip_t *) pgw_ue_ip_alloc(int family, const char *apn); CORE_DECLARE(status_t) pgw_ue_ip_free(pgw_ue_ip_t *ip); CORE_DECLARE(c_uint8_t) pgw_ue_ip_prefixlen(pgw_ue_ip_t *ue_ip); +CORE_DECLARE(pgw_dev_t*) pgw_dev_add(const char *ifname); +CORE_DECLARE(status_t ) pgw_dev_remove(pgw_dev_t *dev); +CORE_DECLARE(status_t ) pgw_dev_remove_all(); +CORE_DECLARE(pgw_dev_t*) pgw_dev_find_by_ifname(const char *ifname); +CORE_DECLARE(pgw_dev_t*) pgw_dev_first(); +CORE_DECLARE(pgw_dev_t*) pgw_dev_next(pgw_dev_t *dev); + +CORE_DECLARE(pgw_subnet_t*) pgw_subnet_add( + const char *ipstr, const char *mask_or_numbits, + const char *apn, const char *ifname); +CORE_DECLARE(status_t ) pgw_subnet_remove(pgw_subnet_t *subnet); +CORE_DECLARE(status_t ) pgw_subnet_remove_all(); +CORE_DECLARE(pgw_subnet_t*) pgw_subnet_first(); +CORE_DECLARE(pgw_subnet_t*) pgw_subnet_next(pgw_subnet_t *subnet); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/src/pgw/pgw_gtp_path.c b/src/pgw/pgw_gtp_path.c index 9dab0958c..756aac53f 100644 --- a/src/pgw/pgw_gtp_path.c +++ b/src/pgw/pgw_gtp_path.c @@ -15,7 +15,7 @@ c_uint16_t in_cksum(c_uint16_t *addr, int len); static status_t pgw_gtp_handle_multicast(pkbuf_t *recvbuf); -static status_t pgw_gtp_handle_slacc(c_uint32_t teid, pkbuf_t *recvbuf); +static status_t pgw_gtp_handle_slacc(pgw_sess_t *sess, pkbuf_t *recvbuf); static status_t pgw_gtp_send_to_bearer(pgw_bearer_t *bearer, pkbuf_t *sendbuf); static status_t pgw_gtp_send_router_advertisement(pgw_sess_t *sess); @@ -102,6 +102,13 @@ static int _gtpv1_u_recv_cb(sock_id sock, void *data) pkbuf_t *pkbuf = NULL; c_uint32_t size = GTPV1U_HEADER_LEN; gtp_header_t *gtp_h = NULL; + struct ip *ip_h = NULL; + + c_uint32_t teid; + pgw_bearer_t *bearer = NULL; + pgw_sess_t *sess = NULL; + pgw_subnet_t *subnet = NULL; + pgw_dev_t *dev = NULL; d_assert(sock, return -1, "Null param"); @@ -119,23 +126,32 @@ static int _gtpv1_u_recv_cb(sock_id sock, void *data) d_trace_hex(50, pkbuf->payload, pkbuf->len); - d_assert(pkbuf->payload, return 0,); + d_assert(pkbuf->payload, goto cleanup,); gtp_h = pkbuf->payload; if (gtp_h->flags & GTPU_FLAGS_S) size += 4; + teid = ntohl(gtp_h->teid); /* Remove GTP header and send packets to TUN interface */ - if (pkbuf_header(pkbuf, -size) != CORE_OK) - { - d_error("pkbuf_header error"); + d_assert(pkbuf_header(pkbuf, -size) == CORE_OK, goto cleanup,); - pkbuf_free(pkbuf); - return -1; - } + ip_h = pkbuf->payload; + d_assert(ip_h, goto cleanup,); + + bearer = pgw_bearer_find_by_pgw_s5u_teid(teid); + d_assert(bearer, goto cleanup,); + sess = bearer->sess; + d_assert(sess, goto cleanup,); + + if (ip_h->ip_v == 4 && sess->ipv4) + subnet = sess->ipv4->subnet; + else if (ip_h->ip_v == 6 && sess->ipv6) + subnet = sess->ipv6->subnet; + d_assert(subnet, goto cleanup,); /* Check IPv6 */ - if (context_self()->parameter.no_slaac == 0) + if (context_self()->parameter.no_slaac == 0 && ip_h->ip_v == 6) { - rv = pgw_gtp_handle_slacc(ntohl(gtp_h->teid), pkbuf); + rv = pgw_gtp_handle_slacc(sess, pkbuf); if (rv == PGW_GTP_HANDLED) { pkbuf_free(pkbuf); @@ -144,11 +160,12 @@ static int _gtpv1_u_recv_cb(sock_id sock, void *data) d_assert(rv == CORE_OK,, "pgw_gtp_handle_slacc() failed"); } - if (sock_write(pgw_self()->tun_sock, pkbuf->payload, pkbuf->len) <= 0) - { - d_error("Can not send packets to tuntap"); - } + dev = subnet->dev; + d_assert(dev, goto cleanup,); + if (sock_write(dev->sock, pkbuf->payload, pkbuf->len) <= 0) + d_error("sock_write() failed"); +cleanup: pkbuf_free(pkbuf); return 0; } @@ -156,7 +173,8 @@ static int _gtpv1_u_recv_cb(sock_id sock, void *data) status_t pgw_gtp_open() { status_t rv; - int i; + pgw_dev_t *dev = NULL; + pgw_subnet_t *subnet = NULL; int rc; rv = gtp_server_list(&pgw_self()->gtpc_list, _gtpv2_c_recv_cb); @@ -193,11 +211,22 @@ status_t pgw_gtp_open() */ /* Open Tun interface */ - rc = tun_open(&pgw_self()->tun_sock, (char *)pgw_self()->tun_ifname, 0); - if (rc != 0) + for (dev = pgw_dev_first(); dev; dev = pgw_dev_next(dev)) { - d_error("Can not open tun(dev : %s)", pgw_self()->tun_ifname); - return CORE_ERROR; + rc = tun_open(&dev->sock, (char *)dev->ifname, 0); + if (rc != 0) + { + d_error("tun_open(dev:%s) failed", dev->ifname); + return CORE_ERROR; + } + + rc = sock_register(dev->sock, _gtpv1_tun_recv_cb, NULL); + if (rc != 0) + { + d_error("sock_register(dev:%s) failed", dev->ifname); + sock_delete(dev->sock); + return CORE_ERROR; + } } /* @@ -211,43 +240,32 @@ status_t pgw_gtp_open() /* Set P-to-P IP address with Netmask * Note that Linux will skip this configuration */ - for (i = 0; i < pgw_self()->num_of_ue_pool; i++) + for (subnet = pgw_subnet_first(); subnet; subnet = pgw_subnet_next(subnet)) { - rc = tun_set_ip(pgw_self()->tun_sock, - pgw_self()->ue_pool[i].ipstr, - pgw_self()->ue_pool[i].mask_or_numbits); + d_assert(subnet->dev, return CORE_ERROR,); + rc = tun_set_ip(subnet->dev->sock, &subnet->gw, &subnet->sub); if (rc != 0) { - d_error("Can not configure tun(dev : %s for %s/%s)", - pgw_self()->tun_ifname, - pgw_self()->ue_pool[i].ipstr, - pgw_self()->ue_pool[i].mask_or_numbits); - + d_error("tun_set_ip(dev:%s) failed", subnet->dev->ifname); return CORE_ERROR; } } - rc = sock_register(pgw_self()->tun_sock, _gtpv1_tun_recv_cb, NULL); - if (rc != 0) - { - d_error("Can not register tun(dev : %s)", - pgw_self()->tun_ifname); - sock_delete(pgw_self()->tun_sock); - return CORE_ERROR; - } - return CORE_OK; } status_t pgw_gtp_close() { + pgw_dev_t *dev = NULL; + sock_delete_list(&pgw_self()->gtpc_list); sock_delete_list(&pgw_self()->gtpc_list6); sock_delete_list(&pgw_self()->gtpu_list); sock_delete_list(&pgw_self()->gtpu_list6); - sock_delete(pgw_self()->tun_sock); + for (dev = pgw_dev_first(); dev; dev = pgw_dev_next(dev)) + sock_delete(dev->sock); return CORE_OK; } @@ -290,11 +308,12 @@ static status_t pgw_gtp_handle_multicast(pkbuf_t *recvbuf) return CORE_OK; } -static status_t pgw_gtp_handle_slacc(c_uint32_t teid, pkbuf_t *recvbuf) +static status_t pgw_gtp_handle_slacc(pgw_sess_t *sess, pkbuf_t *recvbuf) { status_t rv; struct ip *ip_h = NULL; + d_assert(sess, return CORE_ERROR,); d_assert(recvbuf, return CORE_ERROR,); d_assert(recvbuf->payload, return CORE_ERROR,); ip_h = (struct ip *)recvbuf->payload; @@ -307,15 +326,6 @@ static status_t pgw_gtp_handle_slacc(c_uint32_t teid, pkbuf_t *recvbuf) (struct icmp6_hdr *)(recvbuf->payload + sizeof(struct ip6_hdr)); if (icmp_h->icmp6_type == ND_ROUTER_SOLICIT) { - pgw_bearer_t *bearer = NULL; - pgw_sess_t *sess = NULL; - - bearer = pgw_bearer_find_by_pgw_s5u_teid(teid); - d_assert(teid, return CORE_ERROR, - "cannot find teid = %d", teid); - sess = bearer->sess; - d_assert(sess, return CORE_ERROR,); - if (sess->ipv6) { rv = pgw_gtp_send_router_advertisement(sess);