From 0cf2319b9c3d43e48acf62d27626f375b62ce472 Mon Sep 17 00:00:00 2001 From: Sukchan Lee Date: Sun, 17 Dec 2017 04:33:12 +0000 Subject: [PATCH 1/3] pgw dev/subnet context is added --- src/pgw/pgw_context.c | 171 +++++++++++++++++++++++++++++++++++++++++- src/pgw/pgw_context.h | 43 ++++++++++- 2 files changed, 208 insertions(+), 6 deletions(-) diff --git a/src/pgw/pgw_context.c b/src/pgw/pgw_context.c index c96d5a5b0..061c6d297 100644 --- a/src/pgw/pgw_context.c +++ b/src/pgw/pgw_context.c @@ -22,6 +22,9 @@ 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); @@ -57,6 +60,11 @@ 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); @@ -90,8 +98,6 @@ 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])) @@ -105,8 +111,15 @@ status_t pgw_context_final() 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,9 +512,11 @@ 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,); @@ -550,6 +565,10 @@ 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); } @@ -561,6 +580,10 @@ status_t pgw_context_parse_config() 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 { @@ -1310,3 +1333,147 @@ c_uint8_t pgw_ue_ip_prefixlen(pgw_ue_ip_t *ue_ip) return CORE_ERROR,); return atoi(pgw_self()->ue_pool[index].mask_or_numbits); } + +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); + + 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); + + 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); + 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..deb99a947 100644 --- a/src/pgw/pgw_context.h +++ b/src/pgw/pgw_context.h @@ -16,6 +16,9 @@ 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 { @@ -32,6 +35,9 @@ 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 */ @@ -64,11 +70,25 @@ 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 */ +typedef struct _pgw_dev_t { + lnode_t node; - c_uint32_t ue_addr; -} pgw_ip_pool_t; + 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 */ + + pgw_dev_t *dev; +} pgw_subnet_t; typedef struct _pgw_ue_ip_t { c_uint8_t index; /* Pool index */ @@ -223,6 +243,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 */ From 60804c79d6991a5d75059aa0ea9fb4f105dd5626 Mon Sep 17 00:00:00 2001 From: Sukchan Lee Date: Sun, 17 Dec 2017 05:50:24 +0000 Subject: [PATCH 2/3] subnet is tested --- src/pgw/pgw_context.c | 179 +++++++++++++++-------------------------- src/pgw/pgw_context.h | 42 +++++----- src/pgw/pgw_gtp_path.c | 4 + 3 files changed, 91 insertions(+), 134 deletions(-) diff --git a/src/pgw/pgw_context.c b/src/pgw/pgw_context.c index 061c6d297..34f7cb451 100644 --- a/src/pgw/pgw_context.c +++ b/src/pgw/pgw_context.c @@ -30,22 +30,10 @@ 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"); @@ -70,9 +58,6 @@ status_t pgw_context_init() 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; @@ -82,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"); @@ -98,19 +81,6 @@ 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)); - 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(); @@ -518,8 +488,6 @@ status_t pgw_context_parse_config() 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) { @@ -575,12 +543,6 @@ status_t pgw_context_parse_config() 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,); @@ -1154,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++) @@ -1210,128 +1159,117 @@ 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) @@ -1436,6 +1374,11 @@ pgw_subnet_t *pgw_subnet_add( 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; @@ -1446,6 +1389,16 @@ 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; diff --git a/src/pgw/pgw_context.h b/src/pgw/pgw_context.h index deb99a947..2f8b8518c 100644 --- a/src/pgw/pgw_context.h +++ b/src/pgw/pgw_context.h @@ -45,23 +45,10 @@ typedef struct _pgw_context_t { 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 */ @@ -70,6 +57,14 @@ typedef struct _pgw_context_t { hash_t *sess_hash; /* hash table (IMSI+APN) */ } pgw_context_t; +typedef struct _pgw_subnet_t pgw_subnet_t; +typedef struct _pgw_ue_ip_t { + c_uint32_t addr[4]; + + /* Related Context */ + pgw_subnet_t *subnet; +} pgw_ue_ip_t; + typedef struct _pgw_dev_t { lnode_t node; @@ -85,16 +80,21 @@ typedef struct _pgw_subnet_t { 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 */ + 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_ue_ip_t { - c_uint8_t index; /* Pool index */ - c_uint32_t addr[4]; -} pgw_ue_ip_t; - typedef struct _pgw_sess_t { lnode_t node; /**< A node of list_t */ index_t index; /**< An index of this node */ diff --git a/src/pgw/pgw_gtp_path.c b/src/pgw/pgw_gtp_path.c index 9dab0958c..8a8502867 100644 --- a/src/pgw/pgw_gtp_path.c +++ b/src/pgw/pgw_gtp_path.c @@ -156,7 +156,9 @@ static int _gtpv1_u_recv_cb(sock_id sock, void *data) status_t pgw_gtp_open() { status_t rv; +#if 0 int i; +#endif int rc; rv = gtp_server_list(&pgw_self()->gtpc_list, _gtpv2_c_recv_cb); @@ -211,6 +213,7 @@ status_t pgw_gtp_open() /* Set P-to-P IP address with Netmask * Note that Linux will skip this configuration */ +#if 0 for (i = 0; i < pgw_self()->num_of_ue_pool; i++) { rc = tun_set_ip(pgw_self()->tun_sock, @@ -226,6 +229,7 @@ status_t pgw_gtp_open() return CORE_ERROR; } } +#endif rc = sock_register(pgw_self()->tun_sock, _gtpv1_tun_recv_cb, NULL); if (rc != 0) From 8d3330cb7994b038a9bfe12f4a8037165d81f7bf Mon Sep 17 00:00:00 2001 From: Sukchan Lee Date: Sun, 17 Dec 2017 06:36:50 +0000 Subject: [PATCH 3/3] multiple device is added --- lib/core/include/core_network.h | 3 +- lib/core/src/unix/tun.c | 25 +++----- src/pgw/pgw_context.c | 2 + src/pgw/pgw_context.h | 8 +-- src/pgw/pgw_gtp_path.c | 110 +++++++++++++++++--------------- 5 files changed, 72 insertions(+), 76 deletions(-) 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 9211af03c..fd0fcfc9d 100644 --- a/lib/core/src/unix/tun.c +++ b/lib/core/src/unix/tun.c @@ -342,29 +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); - } + if (gw->family == AF_INET) + rv = tun_set_ipv4(id, gw, sub); + else if (gw->family == AF_INET6) + rv = tun_set_ipv6(id, gw, sub); else - { - rv = tun_set_ipv6(id, &ipaddr, &ipsub); - } + d_assert(0, return CORE_ERROR,); return rv; } diff --git a/src/pgw/pgw_context.c b/src/pgw/pgw_context.c index 34f7cb451..4f5a23794 100644 --- a/src/pgw/pgw_context.c +++ b/src/pgw/pgw_context.c @@ -1365,6 +1365,8 @@ pgw_subnet_t *pgw_subnet_add( 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,); diff --git a/src/pgw/pgw_context.h b/src/pgw/pgw_context.h index 2f8b8518c..7d88b2440 100644 --- a/src/pgw/pgw_context.h +++ b/src/pgw/pgw_context.h @@ -22,8 +22,9 @@ extern "C" { 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 */ @@ -43,9 +44,6 @@ typedef struct _pgw_context_t { 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_DNS 2 const char *dns[MAX_NUM_OF_DNS]; /* Primary/Secondanry */ const char *dns6[MAX_NUM_OF_DNS]; /* Primary/Secondanry */ diff --git a/src/pgw/pgw_gtp_path.c b/src/pgw/pgw_gtp_path.c index 8a8502867..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,9 +173,8 @@ static int _gtpv1_u_recv_cb(sock_id sock, void *data) status_t pgw_gtp_open() { status_t rv; -#if 0 - int i; -#endif + pgw_dev_t *dev = NULL; + pgw_subnet_t *subnet = NULL; int rc; rv = gtp_server_list(&pgw_self()->gtpc_list, _gtpv2_c_recv_cb); @@ -195,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; + } } /* @@ -213,45 +240,32 @@ status_t pgw_gtp_open() /* Set P-to-P IP address with Netmask * Note that Linux will skip this configuration */ -#if 0 - 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; } } -#endif - - 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; } @@ -294,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; @@ -311,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);