diff --git a/src/pgw/pgw-context.c b/src/pgw/pgw-context.c index 584f130f4..5dcfd22b3 100644 --- a/src/pgw/pgw-context.c +++ b/src/pgw/pgw-context.c @@ -80,6 +80,8 @@ void pgw_context_init(void) ogs_pool_init(&pgw_pf_pool, ogs_config()->pool.pf); self.sess_hash = ogs_hash_make(); + self.ipv4_hash = ogs_hash_make(); + self.ipv6_hash = ogs_hash_make(); ogs_list_init(&self.sess_list); @@ -97,6 +99,10 @@ void pgw_context_final(void) ogs_assert(self.sess_hash); ogs_hash_destroy(self.sess_hash); + ogs_assert(self.ipv4_hash); + ogs_hash_destroy(self.ipv4_hash); + ogs_assert(self.ipv6_hash); + ogs_hash_destroy(self.ipv6_hash); ogs_pool_final(&pgw_bearer_pool); ogs_pool_final(&pgw_sess_pool); @@ -814,6 +820,7 @@ pgw_sess_t *pgw_sess_add( sess->ipv4 = pgw_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 = pgw_ue_ip_alloc(AF_INET6, apn, (paa->addr6)); ogs_assert(sess->ipv6); @@ -823,6 +830,7 @@ pgw_sess_t *pgw_sess_add( 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 = pgw_ue_ip_alloc(AF_INET, apn, (uint8_t *)&(paa->both.addr)); ogs_assert(sess->ipv4); @@ -835,6 +843,8 @@ pgw_sess_t *pgw_sess_add( 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(); @@ -864,10 +874,14 @@ int pgw_sess_remove(pgw_sess_t *sess) ogs_hash_set(self.sess_hash, sess->hash_keybuf, sess->hash_keylen, NULL); - if (sess->ipv4) + if (sess->ipv4) { + ogs_hash_set(self.ipv4_hash, sess->ipv4->addr, OGS_IPV4_LEN, NULL); pgw_ue_ip_free(sess->ipv4); - if (sess->ipv6) + } + if (sess->ipv6) { + ogs_hash_set(self.ipv6_hash, sess->ipv6->addr, OGS_IPV6_LEN, NULL); pgw_ue_ip_free(sess->ipv6); + } pgw_bearer_remove_all(sess); @@ -909,6 +923,19 @@ pgw_sess_t *pgw_sess_find_by_imsi_apn( return (pgw_sess_t *)ogs_hash_get(self.sess_hash, keybuf, keylen); } +pgw_sess_t *pgw_sess_find_by_ipv4(uint32_t addr) +{ + ogs_assert(self.ipv4_hash); + return (pgw_sess_t *)ogs_hash_get(self.ipv4_hash, &addr, OGS_IPV4_LEN); +} + +pgw_sess_t *pgw_sess_find_by_ipv6(uint32_t *addr6) +{ + ogs_assert(self.ipv6_hash); + ogs_assert(addr6); + return (pgw_sess_t *)ogs_hash_get(self.ipv6_hash, addr6, OGS_IPV6_LEN); +} + pgw_sess_t *pgw_sess_add_by_message(ogs_gtp_message_t *message) { pgw_sess_t *sess = NULL; diff --git a/src/pgw/pgw-context.h b/src/pgw/pgw-context.h index b340d17d6..ef086563e 100644 --- a/src/pgw/pgw-context.h +++ b/src/pgw/pgw-context.h @@ -88,6 +88,8 @@ typedef struct pgw_context_s { ogs_list_t ip_pool_list; ogs_hash_t *sess_hash; /* hash table (IMSI+APN) */ + ogs_hash_t *ipv4_hash; /* hash table (IPv4 Address) */ + ogs_hash_t *ipv6_hash; /* hash table (IPv6 Address) */ ogs_list_t sess_list; } pgw_context_t; @@ -246,6 +248,8 @@ void pgw_sess_remove_all(void); pgw_sess_t *pgw_sess_find(uint32_t index); pgw_sess_t *pgw_sess_find_by_teid(uint32_t teid); pgw_sess_t *pgw_sess_find_by_imsi_apn(uint8_t *imsi, int imsi_len, char *apn); +pgw_sess_t *pgw_sess_find_by_ipv4(uint32_t addr); +pgw_sess_t *pgw_sess_find_by_ipv6(uint32_t *addr6); pgw_bearer_t *pgw_bearer_add(pgw_sess_t *sess); int pgw_bearer_remove(pgw_bearer_t *bearer); diff --git a/src/pgw/pgw-ipfw.c b/src/pgw/pgw-ipfw.c index b13e175b7..fd5d7fa99 100644 --- a/src/pgw/pgw-ipfw.c +++ b/src/pgw/pgw-ipfw.c @@ -261,7 +261,9 @@ pgw_bearer_t *pgw_bearer_find_by_packet(ogs_pkbuf_t *pkt) src_addr = &ip_h->ip_src.s_addr; dst_addr = &ip_h->ip_dst.s_addr; - addr_len = 4; + addr_len = OGS_IPV4_LEN; + + sess = pgw_sess_find_by_ipv4(dst_addr[0]); } else if (ip_h->ip_v == 6) { ip_h = NULL; ip6_h = (struct ip6_hdr *)pkt->data; @@ -270,8 +272,9 @@ pgw_bearer_t *pgw_bearer_find_by_packet(ogs_pkbuf_t *pkt) src_addr = (uint32_t *)ip6_h->ip6_src.s6_addr; dst_addr = (uint32_t *)ip6_h->ip6_dst.s6_addr; - addr_len = 16; + addr_len = OGS_IPV6_LEN; + sess = pgw_sess_find_by_ipv6(dst_addr); } else ogs_error("Invalid IP version = %d", ip_h->ip_v); @@ -282,178 +285,168 @@ pgw_bearer_t *pgw_bearer_find_by_packet(ogs_pkbuf_t *pkt) ip_hlen, ntohl(dst_addr[0]), ntohl(dst_addr[1]), ntohl(dst_addr[2]), ntohl(dst_addr[3])); + if (sess) { + pgw_bearer_t *default_bearer = NULL; + pgw_bearer_t *bearer = NULL; - /* TODO: Need to use the method of FAST matching algorithm and - * implementation . - * Until be ready, linear searching will be use to find the bearer. - */ - - ogs_list_for_each(&pgw_self()->sess_list, sess) { - if (sess->ipv4) + if (ip_h && sess->ipv4) ogs_debug("[PGW] PAA IPv4:%s", INET_NTOP(&sess->ipv4->addr, buf)); - if (sess->ipv6) + if (ip6_h && sess->ipv6) ogs_debug("[PGW] PAA IPv6:%s", INET6_NTOP(&sess->ipv6->addr, buf)); - if ((sess->ipv4 && memcmp(dst_addr, sess->ipv4->addr, addr_len) == 0) || - (sess->ipv6 && memcmp(dst_addr, sess->ipv6->addr, addr_len) == 0)) { - pgw_bearer_t *default_bearer = NULL; - pgw_bearer_t *bearer = NULL; + /* Save the default bearer */ + default_bearer = pgw_default_bearer_in_sess(sess); + ogs_assert(default_bearer); - /* Save the default bearer */ - default_bearer = pgw_default_bearer_in_sess(sess); - ogs_assert(default_bearer); + /* Found */ + ogs_debug("[PGW] Found Session : EBI[%d]", default_bearer->ebi); - /* Found */ - ogs_debug("[PGW] Found Session : EBI[%d]", default_bearer->ebi); + bearer = pgw_bearer_next(default_bearer); + /* Find the bearer with matched */ + for (; bearer; bearer = pgw_bearer_next(bearer)) { + pgw_pf_t *pf = NULL; - bearer = pgw_bearer_next(default_bearer); - /* Find the bearer with matched */ - for (; bearer; bearer = pgw_bearer_next(bearer)) { - pgw_pf_t *pf = NULL; + if (bearer->ebi == 0) { + /* Create Bearer Response is not received */ + continue; + } - if (bearer->ebi == 0) { - /* Create Bearer Response is not received */ + for (pf = pgw_pf_first(bearer); pf; pf = pgw_pf_next(pf)) { + int k; + uint32_t src_mask[4]; + uint32_t dst_mask[4]; + + ogs_debug("DIR:%d PROTO:%d SRC:%d-%d DST:%d-%d", + pf->direction, pf->rule.proto, + pf->rule.port.local.low, + pf->rule.port.local.high, + pf->rule.port.remote.low, + pf->rule.port.remote.high); + ogs_debug("SRC:%08x %08x %08x %08x/%08x %08x %08x %08x", + ntohl(pf->rule.ip.local.addr[0]), + ntohl(pf->rule.ip.local.addr[1]), + ntohl(pf->rule.ip.local.addr[2]), + ntohl(pf->rule.ip.local.addr[3]), + ntohl(pf->rule.ip.local.mask[0]), + ntohl(pf->rule.ip.local.mask[1]), + ntohl(pf->rule.ip.local.mask[2]), + ntohl(pf->rule.ip.local.mask[3])); + ogs_debug("DST:%08x %08x %08x %08x/%08x %08x %08x %08x", + ntohl(pf->rule.ip.remote.addr[0]), + ntohl(pf->rule.ip.remote.addr[1]), + ntohl(pf->rule.ip.remote.addr[2]), + ntohl(pf->rule.ip.remote.addr[3]), + ntohl(pf->rule.ip.remote.mask[0]), + ntohl(pf->rule.ip.remote.mask[1]), + ntohl(pf->rule.ip.remote.mask[2]), + ntohl(pf->rule.ip.remote.mask[3])); + + if (pf->direction != 1) { continue; } - for (pf = pgw_pf_first(bearer); pf; pf = pgw_pf_next(pf)) { - int k; - uint32_t src_mask[4]; - uint32_t dst_mask[4]; + for (k = 0; k < 4; k++) { + src_mask[k] = src_addr[k] & pf->rule.ip.local.mask[k]; + dst_mask[k] = dst_addr[k] & pf->rule.ip.remote.mask[k]; + } - ogs_debug("DIR:%d PROTO:%d SRC:%d-%d DST:%d-%d", - pf->direction, pf->rule.proto, - pf->rule.port.local.low, - pf->rule.port.local.high, - pf->rule.port.remote.low, - pf->rule.port.remote.high); - ogs_debug("SRC:%08x %08x %08x %08x/%08x %08x %08x %08x", - ntohl(pf->rule.ip.local.addr[0]), - ntohl(pf->rule.ip.local.addr[1]), - ntohl(pf->rule.ip.local.addr[2]), - ntohl(pf->rule.ip.local.addr[3]), - ntohl(pf->rule.ip.local.mask[0]), - ntohl(pf->rule.ip.local.mask[1]), - ntohl(pf->rule.ip.local.mask[2]), - ntohl(pf->rule.ip.local.mask[3])); - ogs_debug("DST:%08x %08x %08x %08x/%08x %08x %08x %08x", - ntohl(pf->rule.ip.remote.addr[0]), - ntohl(pf->rule.ip.remote.addr[1]), - ntohl(pf->rule.ip.remote.addr[2]), - ntohl(pf->rule.ip.remote.addr[3]), - ntohl(pf->rule.ip.remote.mask[0]), - ntohl(pf->rule.ip.remote.mask[1]), - ntohl(pf->rule.ip.remote.mask[2]), - ntohl(pf->rule.ip.remote.mask[3])); - - if (pf->direction != 1) { - continue; + if (memcmp(src_mask, pf->rule.ip.local.addr, + addr_len) == 0 && + memcmp(dst_mask, pf->rule.ip.remote.addr, + addr_len) == 0) { + /* Protocol match */ + if (pf->rule.proto == 0) { /* IP */ + /* No need to match port */ + break; } - for (k = 0; k < 4; k++) { - src_mask[k] = src_addr[k] & pf->rule.ip.local.mask[k]; - dst_mask[k] = dst_addr[k] & pf->rule.ip.remote.mask[k]; - } + if (pf->rule.proto == proto) { + if (pf->rule.proto == IPPROTO_TCP) { + struct tcphdr *tcph = + (struct tcphdr *) + ((char *)pkt->data + ip_hlen); - if (memcmp(src_mask, pf->rule.ip.local.addr, - addr_len) == 0 && - memcmp(dst_mask, pf->rule.ip.remote.addr, - addr_len) == 0) { - /* Protocol match */ - if (pf->rule.proto == 0) { /* IP */ + /* Source port */ + if (pf->rule.port.local.low && + ntohs(tcph->th_sport) < + pf->rule.port.local.low) { + continue; + } + + if (pf->rule.port.local.high && + ntohs(tcph->th_sport) > + pf->rule.port.local.high) { + continue; + } + + /* Dst Port*/ + if (pf->rule.port.remote.low && + ntohs(tcph->th_dport) < + pf->rule.port.remote.low) { + continue; + } + + if (pf->rule.port.remote.high && + ntohs(tcph->th_dport) > + pf->rule.port.remote.high) { + continue; + } + + /* Matched */ + break; + } else if (pf->rule.proto == IPPROTO_UDP) { + struct udphdr *udph = + (struct udphdr *) + ((char *)pkt->data + ip_hlen); + + /* Source port */ + if (pf->rule.port.local.low && + ntohs(udph->uh_sport) < + pf->rule.port.local.low) { + continue; + } + + if (pf->rule.port.local.high && + ntohs(udph->uh_sport) > + pf->rule.port.local.high) { + continue; + } + + /* Dst Port*/ + if (pf->rule.port.remote.low && + ntohs(udph->uh_dport) < + pf->rule.port.remote.low) { + continue; + } + + if (pf->rule.port.remote.high && + ntohs(udph->uh_dport) > + pf->rule.port.remote.high) { + continue; + } + + /* Matched */ + break; + } else { /* No need to match port */ break; } - - if (pf->rule.proto == proto) { - if (pf->rule.proto == IPPROTO_TCP) { - struct tcphdr *tcph = - (struct tcphdr *) - ((char *)pkt->data + ip_hlen); - - /* Source port */ - if (pf->rule.port.local.low && - ntohs(tcph->th_sport) < - pf->rule.port.local.low) { - continue; - } - - if (pf->rule.port.local.high && - ntohs(tcph->th_sport) > - pf->rule.port.local.high) { - continue; - } - - /* Dst Port*/ - if (pf->rule.port.remote.low && - ntohs(tcph->th_dport) < - pf->rule.port.remote.low) { - continue; - } - - if (pf->rule.port.remote.high && - ntohs(tcph->th_dport) > - pf->rule.port.remote.high) { - continue; - } - - /* Matched */ - break; - } else if (pf->rule.proto == IPPROTO_UDP) { - struct udphdr *udph = - (struct udphdr *) - ((char *)pkt->data + ip_hlen); - - /* Source port */ - if (pf->rule.port.local.low && - ntohs(udph->uh_sport) < - pf->rule.port.local.low) { - continue; - } - - if (pf->rule.port.local.high && - ntohs(udph->uh_sport) > - pf->rule.port.local.high) { - continue; - } - - /* Dst Port*/ - if (pf->rule.port.remote.low && - ntohs(udph->uh_dport) < - pf->rule.port.remote.low) { - continue; - } - - if (pf->rule.port.remote.high && - ntohs(udph->uh_dport) > - pf->rule.port.remote.high) { - continue; - } - - /* Matched */ - break; - } else { - /* No need to match port */ - break; - } - - } } - } - - if (pf) { - bearer = pf->bearer; - ogs_debug("Found Dedicated Bearer : EBI[%d]", bearer->ebi); - break; - } - } - return (bearer ? bearer : default_bearer); + if (pf) { + bearer = pf->bearer; + ogs_debug("Found Dedicated Bearer : EBI[%d]", bearer->ebi); + break; + } } + + return (bearer ? bearer : default_bearer); + } else { + ogs_debug("[PGW] No Session"); } return NULL; diff --git a/tests/simple/attach-test.c b/tests/simple/attach-test.c index 635f44a96..9fc2c77c7 100644 --- a/tests/simple/attach-test.c +++ b/tests/simple/attach-test.c @@ -266,7 +266,7 @@ static void attach_test1(abts_case *tc, void *data) ABTS_PTR_NOTNULL(tc, recvbuf); ogs_pkbuf_free(recvbuf); -#if LINUX == 1 +#if __linux__ rv = testgtpu_build_ping(&sendbuf, "cafe::2", "cafe::1"); ABTS_INT_EQUAL(tc, OGS_OK, rv); rv = testenb_gtpu_send(gtpu, sendbuf);