forked from acouzens/open5gs
[UPF] Handle framed routes
This commit is contained in:
parent
3e980e006f
commit
990abbab2c
|
@ -1004,6 +1004,8 @@ void ogs_pfcp_pdr_associate_qer(ogs_pfcp_pdr_t *pdr, ogs_pfcp_qer_t *qer)
|
||||||
|
|
||||||
void ogs_pfcp_pdr_remove(ogs_pfcp_pdr_t *pdr)
|
void ogs_pfcp_pdr_remove(ogs_pfcp_pdr_t *pdr)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
ogs_assert(pdr);
|
ogs_assert(pdr);
|
||||||
ogs_assert(pdr->sess);
|
ogs_assert(pdr->sess);
|
||||||
|
|
||||||
|
@ -1033,6 +1035,24 @@ void ogs_pfcp_pdr_remove(ogs_pfcp_pdr_t *pdr)
|
||||||
if (pdr->id_node)
|
if (pdr->id_node)
|
||||||
ogs_pool_free(&pdr->sess->pdr_id_pool, pdr->id_node);
|
ogs_pool_free(&pdr->sess->pdr_id_pool, pdr->id_node);
|
||||||
|
|
||||||
|
if (pdr->ipv4_framed_routes) {
|
||||||
|
for (i = 0; i < OGS_MAX_NUM_OF_FRAMED_ROUTES_IN_PDI; i++) {
|
||||||
|
if (!pdr->ipv4_framed_routes[i])
|
||||||
|
break;
|
||||||
|
ogs_free(pdr->ipv4_framed_routes[i]);
|
||||||
|
}
|
||||||
|
ogs_free(pdr->ipv4_framed_routes);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pdr->ipv6_framed_routes) {
|
||||||
|
for (i = 0; i < OGS_MAX_NUM_OF_FRAMED_ROUTES_IN_PDI; i++) {
|
||||||
|
if (!pdr->ipv6_framed_routes[i])
|
||||||
|
break;
|
||||||
|
ogs_free(pdr->ipv6_framed_routes[i]);
|
||||||
|
}
|
||||||
|
ogs_free(pdr->ipv6_framed_routes);
|
||||||
|
}
|
||||||
|
|
||||||
ogs_pool_free(&ogs_pfcp_pdr_pool, pdr);
|
ogs_pool_free(&ogs_pfcp_pdr_pool, pdr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -160,6 +160,9 @@ typedef struct ogs_pfcp_pdr_s {
|
||||||
ogs_pfcp_ue_ip_addr_t ue_ip_addr;
|
ogs_pfcp_ue_ip_addr_t ue_ip_addr;
|
||||||
int ue_ip_addr_len;
|
int ue_ip_addr_len;
|
||||||
|
|
||||||
|
char **ipv4_framed_routes;
|
||||||
|
char **ipv6_framed_routes;
|
||||||
|
|
||||||
ogs_pfcp_f_teid_t f_teid;
|
ogs_pfcp_f_teid_t f_teid;
|
||||||
int f_teid_len;
|
int f_teid_len;
|
||||||
|
|
||||||
|
|
|
@ -478,6 +478,58 @@ ogs_pfcp_pdr_t *ogs_pfcp_handle_create_pdr(ogs_pfcp_sess_t *sess,
|
||||||
pdr->ue_ip_addr_len);
|
pdr->ue_ip_addr_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < OGS_MAX_NUM_OF_FRAMED_ROUTES_IN_PDI; i++) {
|
||||||
|
if (!pdr->ipv4_framed_routes || !pdr->ipv4_framed_routes[i])
|
||||||
|
break;
|
||||||
|
ogs_free(pdr->ipv4_framed_routes[i]);
|
||||||
|
pdr->ipv4_framed_routes[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < OGS_MAX_NUM_OF_FRAMED_ROUTES_IN_PDI; i++) {
|
||||||
|
if (!pdr->ipv6_framed_routes || !pdr->ipv6_framed_routes[i])
|
||||||
|
break;
|
||||||
|
ogs_free(pdr->ipv6_framed_routes[i]);
|
||||||
|
pdr->ipv6_framed_routes[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < OGS_MAX_NUM_OF_FRAMED_ROUTES_IN_PDI; i++) {
|
||||||
|
char *route;
|
||||||
|
|
||||||
|
if (!message->pdi.framed_route[i].presence)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!pdr->ipv4_framed_routes) {
|
||||||
|
pdr->ipv4_framed_routes = ogs_calloc(
|
||||||
|
OGS_MAX_NUM_OF_FRAMED_ROUTES_IN_PDI, sizeof(pdr->ipv4_framed_routes[0]));
|
||||||
|
ogs_assert(pdr->ipv4_framed_routes);
|
||||||
|
}
|
||||||
|
route = ogs_malloc(message->pdi.framed_route[i].len + 1);
|
||||||
|
ogs_assert(route);
|
||||||
|
memcpy(route, message->pdi.framed_route[i].data,
|
||||||
|
message->pdi.framed_route[i].len);
|
||||||
|
route[message->pdi.framed_route[i].len] = '\0';
|
||||||
|
pdr->ipv4_framed_routes[i] = route;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < OGS_MAX_NUM_OF_FRAMED_ROUTES_IN_PDI; i++) {
|
||||||
|
char *route;
|
||||||
|
|
||||||
|
if (!message->pdi.framed_ipv6_route[i].presence)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!pdr->ipv6_framed_routes) {
|
||||||
|
pdr->ipv6_framed_routes = ogs_calloc(
|
||||||
|
OGS_MAX_NUM_OF_FRAMED_ROUTES_IN_PDI, sizeof(ogs_ipsubnet_t));
|
||||||
|
ogs_assert(pdr->ipv6_framed_routes);
|
||||||
|
}
|
||||||
|
route = ogs_malloc(message->pdi.framed_ipv6_route[i].len + 1);
|
||||||
|
ogs_assert(route);
|
||||||
|
memcpy(route, message->pdi.framed_ipv6_route[i].data,
|
||||||
|
message->pdi.framed_ipv6_route[i].len);
|
||||||
|
route[message->pdi.framed_ipv6_route[i].len] = '\0';
|
||||||
|
pdr->ipv6_framed_routes[i] = route;
|
||||||
|
}
|
||||||
|
|
||||||
memset(&pdr->outer_header_removal, 0, sizeof(pdr->outer_header_removal));
|
memset(&pdr->outer_header_removal, 0, sizeof(pdr->outer_header_removal));
|
||||||
pdr->outer_header_removal_len = 0;
|
pdr->outer_header_removal_len = 0;
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ void upf_context_init(void)
|
||||||
ogs_pfcp_self()->up_function_features.empu = 1;
|
ogs_pfcp_self()->up_function_features.empu = 1;
|
||||||
ogs_pfcp_self()->up_function_features.mnop = 1;
|
ogs_pfcp_self()->up_function_features.mnop = 1;
|
||||||
ogs_pfcp_self()->up_function_features.vtime = 1;
|
ogs_pfcp_self()->up_function_features.vtime = 1;
|
||||||
|
ogs_pfcp_self()->up_function_features.frrt = 1;
|
||||||
ogs_pfcp_self()->up_function_features_len = 4;
|
ogs_pfcp_self()->up_function_features_len = 4;
|
||||||
|
|
||||||
ogs_list_init(&self.sess_list);
|
ogs_list_init(&self.sess_list);
|
||||||
|
@ -61,6 +62,15 @@ void upf_context_init(void)
|
||||||
context_initialized = 1;
|
context_initialized = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void free_upf_route_trie_node(struct upf_route_trie_node *node)
|
||||||
|
{
|
||||||
|
if (!node)
|
||||||
|
return;
|
||||||
|
free_upf_route_trie_node(node->left);
|
||||||
|
free_upf_route_trie_node(node->right);
|
||||||
|
ogs_free(node);
|
||||||
|
}
|
||||||
|
|
||||||
void upf_context_final(void)
|
void upf_context_final(void)
|
||||||
{
|
{
|
||||||
ogs_assert(context_initialized == 1);
|
ogs_assert(context_initialized == 1);
|
||||||
|
@ -76,6 +86,9 @@ void upf_context_final(void)
|
||||||
ogs_assert(self.ipv6_hash);
|
ogs_assert(self.ipv6_hash);
|
||||||
ogs_hash_destroy(self.ipv6_hash);
|
ogs_hash_destroy(self.ipv6_hash);
|
||||||
|
|
||||||
|
free_upf_route_trie_node(self.ipv4_framed_routes);
|
||||||
|
free_upf_route_trie_node(self.ipv6_framed_routes);
|
||||||
|
|
||||||
ogs_pool_final(&upf_sess_pool);
|
ogs_pool_final(&upf_sess_pool);
|
||||||
|
|
||||||
context_initialized = 0;
|
context_initialized = 0;
|
||||||
|
@ -208,6 +221,9 @@ int upf_sess_remove(upf_sess_t *sess)
|
||||||
ogs_pfcp_ue_ip_free(sess->ipv6);
|
ogs_pfcp_ue_ip_free(sess->ipv6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
upf_sess_set_ue_ipv4_framed_routes(sess, NULL);
|
||||||
|
upf_sess_set_ue_ipv6_framed_routes(sess, NULL);
|
||||||
|
|
||||||
ogs_pfcp_pool_final(&sess->pfcp);
|
ogs_pfcp_pool_final(&sess->pfcp);
|
||||||
|
|
||||||
ogs_pool_free(&upf_sess_pool, sess);
|
ogs_pool_free(&upf_sess_pool, sess);
|
||||||
|
@ -259,16 +275,66 @@ upf_sess_t *upf_sess_find_by_upf_n4_seid(uint64_t seid)
|
||||||
|
|
||||||
upf_sess_t *upf_sess_find_by_ipv4(uint32_t addr)
|
upf_sess_t *upf_sess_find_by_ipv4(uint32_t addr)
|
||||||
{
|
{
|
||||||
|
upf_sess_t *ret;
|
||||||
|
struct upf_route_trie_node *trie = self.ipv4_framed_routes;
|
||||||
|
const int nbits = sizeof(addr) << 3;
|
||||||
|
int i;
|
||||||
|
|
||||||
ogs_assert(self.ipv4_hash);
|
ogs_assert(self.ipv4_hash);
|
||||||
return (upf_sess_t *)ogs_hash_get(self.ipv4_hash, &addr, OGS_IPV4_LEN);
|
|
||||||
|
ret = ogs_hash_get(self.ipv4_hash, &addr, OGS_IPV4_LEN);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
for (i = 0; i <= nbits; i++) {
|
||||||
|
int bit = nbits - i - 1;
|
||||||
|
|
||||||
|
if (!trie)
|
||||||
|
break;
|
||||||
|
if (trie->sess)
|
||||||
|
ret = trie->sess;
|
||||||
|
if (i == nbits)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if ((1 << bit) & be32toh(addr))
|
||||||
|
trie = trie->right;
|
||||||
|
else
|
||||||
|
trie = trie->left;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
upf_sess_t *upf_sess_find_by_ipv6(uint32_t *addr6)
|
upf_sess_t *upf_sess_find_by_ipv6(uint32_t *addr6)
|
||||||
{
|
{
|
||||||
|
upf_sess_t *ret = NULL;
|
||||||
|
struct upf_route_trie_node *trie = self.ipv6_framed_routes;
|
||||||
|
int i;
|
||||||
|
const int chunk_size = sizeof(*addr6) << 3;
|
||||||
|
|
||||||
ogs_assert(self.ipv6_hash);
|
ogs_assert(self.ipv6_hash);
|
||||||
ogs_assert(addr6);
|
ogs_assert(addr6);
|
||||||
return (upf_sess_t *)ogs_hash_get(
|
ret = ogs_hash_get(
|
||||||
self.ipv6_hash, addr6, OGS_IPV6_DEFAULT_PREFIX_LEN >> 3);
|
self.ipv6_hash, addr6, OGS_IPV6_DEFAULT_PREFIX_LEN >> 3);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
for (i = 0; i <= OGS_IPV6_128_PREFIX_LEN; i++) {
|
||||||
|
int part = i / chunk_size;
|
||||||
|
int bit = (OGS_IPV6_128_PREFIX_LEN - i - 1) % chunk_size;
|
||||||
|
|
||||||
|
if (!trie)
|
||||||
|
break;
|
||||||
|
if (trie->sess)
|
||||||
|
ret = trie->sess;
|
||||||
|
if (i == OGS_IPV6_128_PREFIX_LEN)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if ((1 << bit) & be32toh(addr6[part]))
|
||||||
|
trie = trie->right;
|
||||||
|
else
|
||||||
|
trie = trie->left;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
upf_sess_t *upf_sess_add_by_message(ogs_pfcp_message_t *message)
|
upf_sess_t *upf_sess_add_by_message(ogs_pfcp_message_t *message)
|
||||||
|
@ -408,6 +474,184 @@ uint8_t upf_sess_set_ue_ip(upf_sess_t *sess,
|
||||||
return cause_value;
|
return cause_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Remove amd free framed ROUTE from TRIE. It isn't an error if the framed
|
||||||
|
route doesn't exist in TRIE. */
|
||||||
|
static void free_framed_route_from_trie(ogs_ipsubnet_t *route)
|
||||||
|
{
|
||||||
|
const int chunk_size = sizeof(route->sub[0]) << 3;
|
||||||
|
const int is_ipv4 = route->family == AF_INET;
|
||||||
|
const int nbits = is_ipv4 ? chunk_size : OGS_IPV6_128_PREFIX_LEN;
|
||||||
|
struct upf_route_trie_node **trie =
|
||||||
|
is_ipv4 ? &self.ipv4_framed_routes : &self.ipv6_framed_routes;
|
||||||
|
|
||||||
|
struct upf_route_trie_node **to_free_tries[OGS_IPV6_128_PREFIX_LEN + 1];
|
||||||
|
int free_from = 0;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (i = 0; i <= nbits; i++) {
|
||||||
|
int part = i / chunk_size;
|
||||||
|
int bit = (nbits - i - 1) % chunk_size;
|
||||||
|
|
||||||
|
if (!*trie)
|
||||||
|
break;
|
||||||
|
to_free_tries[i] = trie;
|
||||||
|
|
||||||
|
if (i == nbits ||
|
||||||
|
((1 << bit) & be32toh(route->mask[part])) == 0) {
|
||||||
|
(*trie)->sess = NULL;
|
||||||
|
if ((*trie)->left || (*trie)->right)
|
||||||
|
free_from = i + 1;
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((1 << bit) & be32toh(route->sub[part])) {
|
||||||
|
if ((*trie)->left || (*trie)->sess)
|
||||||
|
free_from = i + 1;
|
||||||
|
trie = &(*trie)->right;
|
||||||
|
} else {
|
||||||
|
if ((*trie)->right || (*trie)->sess)
|
||||||
|
free_from = i + 1;
|
||||||
|
trie = &(*trie)->left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = i - 1; i >= free_from; i--) {
|
||||||
|
trie = to_free_tries[i];
|
||||||
|
ogs_free(*trie);
|
||||||
|
*trie = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_framed_route_to_trie(ogs_ipsubnet_t *route, upf_sess_t *sess)
|
||||||
|
{
|
||||||
|
const int chunk_size = sizeof(route->sub[0]) << 3;
|
||||||
|
const int is_ipv4 = route->family == AF_INET;
|
||||||
|
const int nbits = is_ipv4 ? chunk_size : OGS_IPV6_128_PREFIX_LEN;
|
||||||
|
struct upf_route_trie_node **trie =
|
||||||
|
is_ipv4 ? &self.ipv4_framed_routes : &self.ipv6_framed_routes;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (i = 0; i <= nbits; i++) {
|
||||||
|
int part = i / chunk_size;
|
||||||
|
int bit = (- i - 1) % chunk_size;
|
||||||
|
|
||||||
|
if (!*trie)
|
||||||
|
*trie = ogs_calloc(1, sizeof(**trie));
|
||||||
|
|
||||||
|
if (i == nbits ||
|
||||||
|
((1 << bit) & be32toh(route->mask[part])) == 0) {
|
||||||
|
(*trie)->sess = sess;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((1 << bit) & be32toh(route->sub[part])) {
|
||||||
|
trie = &(*trie)->right;
|
||||||
|
} else {
|
||||||
|
trie = &(*trie)->left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_framed_route(ogs_ipsubnet_t *subnet, const char *framed_route)
|
||||||
|
{
|
||||||
|
char *mask = ogs_strdup(framed_route);
|
||||||
|
char *addr = strsep(&mask, "/");
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
rv = ogs_ipsubnet(subnet, addr, mask);
|
||||||
|
ogs_free(addr);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t upf_sess_set_ue_ipv4_framed_routes(upf_sess_t *sess,
|
||||||
|
char *framed_routes[])
|
||||||
|
{
|
||||||
|
int i = 0, j = 0, rv;
|
||||||
|
uint8_t cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED;
|
||||||
|
|
||||||
|
ogs_assert(sess);
|
||||||
|
|
||||||
|
for (i = 0; i < OGS_MAX_NUM_OF_FRAMED_ROUTES_IN_PDI; i++) {
|
||||||
|
if (!sess->ipv4_framed_routes || !sess->ipv4_framed_routes[i].family)
|
||||||
|
break;
|
||||||
|
free_framed_route_from_trie(&sess->ipv4_framed_routes[i]);
|
||||||
|
memset(&sess->ipv4_framed_routes[i], 0,
|
||||||
|
sizeof(sess->ipv4_framed_routes[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0, j = 0; i < OGS_MAX_NUM_OF_FRAMED_ROUTES_IN_PDI; i++) {
|
||||||
|
if (!framed_routes || !framed_routes[i])
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (sess->ipv4_framed_routes == NULL) {
|
||||||
|
sess->ipv4_framed_routes = ogs_calloc(
|
||||||
|
OGS_MAX_NUM_OF_FRAMED_ROUTES_IN_PDI, sizeof(ogs_ipsubnet_t));
|
||||||
|
ogs_assert(sess->ipv4_framed_routes);
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = parse_framed_route(&sess->ipv4_framed_routes[j], framed_routes[i]);
|
||||||
|
|
||||||
|
if (rv != OGS_OK) {
|
||||||
|
ogs_warn("Ignoring invalid framed route %s", framed_routes[i]);
|
||||||
|
memset(&sess->ipv4_framed_routes[j], 0,
|
||||||
|
sizeof(sess->ipv4_framed_routes[j]));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
add_framed_route_to_trie(&sess->ipv4_framed_routes[j], sess);
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
if (j == 0 && sess->ipv4_framed_routes) {
|
||||||
|
ogs_free(sess->ipv4_framed_routes);
|
||||||
|
sess->ipv4_framed_routes = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cause_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t upf_sess_set_ue_ipv6_framed_routes(upf_sess_t *sess,
|
||||||
|
char *framed_routes[])
|
||||||
|
{
|
||||||
|
int i = 0, j = 0, rv;
|
||||||
|
uint8_t cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED;
|
||||||
|
|
||||||
|
ogs_assert(sess);
|
||||||
|
|
||||||
|
for (i = 0; i < OGS_MAX_NUM_OF_FRAMED_ROUTES_IN_PDI; i++) {
|
||||||
|
if (!sess->ipv6_framed_routes || !sess->ipv6_framed_routes[i].family)
|
||||||
|
break;
|
||||||
|
free_framed_route_from_trie(&sess->ipv6_framed_routes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0, j = 0; i < OGS_MAX_NUM_OF_FRAMED_ROUTES_IN_PDI; i++) {
|
||||||
|
if (!framed_routes || !framed_routes[i])
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (sess->ipv6_framed_routes == NULL) {
|
||||||
|
sess->ipv6_framed_routes = ogs_calloc(
|
||||||
|
OGS_MAX_NUM_OF_FRAMED_ROUTES_IN_PDI, sizeof(ogs_ipsubnet_t));
|
||||||
|
ogs_assert(sess->ipv6_framed_routes);
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = parse_framed_route(&sess->ipv6_framed_routes[j], framed_routes[i]);
|
||||||
|
|
||||||
|
if (rv != OGS_OK) {
|
||||||
|
ogs_warn("Ignoring invalid framed route %s", framed_routes[i]);
|
||||||
|
memset(&sess->ipv6_framed_routes[j], 0,
|
||||||
|
sizeof(sess->ipv6_framed_routes[j]));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
add_framed_route_to_trie(&sess->ipv6_framed_routes[j], sess);
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
if (j == 0 && sess->ipv6_framed_routes) {
|
||||||
|
ogs_free(sess->ipv6_framed_routes);
|
||||||
|
sess->ipv6_framed_routes = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cause_value;
|
||||||
|
}
|
||||||
|
|
||||||
void upf_sess_urr_acc_add(upf_sess_t *sess, ogs_pfcp_urr_t *urr, size_t size, bool is_uplink)
|
void upf_sess_urr_acc_add(upf_sess_t *sess, ogs_pfcp_urr_t *urr, size_t size, bool is_uplink)
|
||||||
{
|
{
|
||||||
upf_sess_urr_acc_t *urr_acc = &sess->urr_acc[urr->id];
|
upf_sess_urr_acc_t *urr_acc = &sess->urr_acc[urr->id];
|
||||||
|
|
|
@ -45,15 +45,26 @@ extern int __upf_log_domain;
|
||||||
#undef OGS_LOG_DOMAIN
|
#undef OGS_LOG_DOMAIN
|
||||||
#define OGS_LOG_DOMAIN __upf_log_domain
|
#define OGS_LOG_DOMAIN __upf_log_domain
|
||||||
|
|
||||||
typedef struct upf_context_s {
|
struct upf_route_trie_node;
|
||||||
ogs_hash_t *seid_hash; /* hash table (SEID) */
|
|
||||||
ogs_hash_t *f_seid_hash; /* hash table (F-SEID) */
|
|
||||||
ogs_hash_t *ipv4_hash; /* hash table (IPv4 Address) */
|
|
||||||
ogs_hash_t *ipv6_hash; /* hash table (IPv6 Address) */
|
|
||||||
|
|
||||||
ogs_list_t sess_list;
|
typedef struct upf_context_s {
|
||||||
|
ogs_hash_t *seid_hash; /* hash table (SEID) */
|
||||||
|
ogs_hash_t *f_seid_hash; /* hash table (F-SEID) */
|
||||||
|
ogs_hash_t *ipv4_hash; /* hash table (IPv4 Address) */
|
||||||
|
ogs_hash_t *ipv6_hash; /* hash table (IPv6 Address) */
|
||||||
|
struct upf_route_trie_node *ipv4_framed_routes; /* IPv4 framed routes trie */
|
||||||
|
struct upf_route_trie_node *ipv6_framed_routes; /* IPv6 framed routes trie */
|
||||||
|
|
||||||
|
ogs_list_t sess_list;
|
||||||
} upf_context_t;
|
} upf_context_t;
|
||||||
|
|
||||||
|
/* trie mapping from IP framed routes to session. */
|
||||||
|
struct upf_route_trie_node {
|
||||||
|
struct upf_route_trie_node *left;
|
||||||
|
struct upf_route_trie_node *right;
|
||||||
|
upf_sess_t *sess;
|
||||||
|
};
|
||||||
|
|
||||||
/* Accounting: */
|
/* Accounting: */
|
||||||
typedef struct upf_sess_urr_acc_s {
|
typedef struct upf_sess_urr_acc_s {
|
||||||
bool reporting_enabled;
|
bool reporting_enabled;
|
||||||
|
@ -99,6 +110,9 @@ typedef struct upf_sess_s {
|
||||||
ogs_pfcp_ue_ip_t *ipv4;
|
ogs_pfcp_ue_ip_t *ipv4;
|
||||||
ogs_pfcp_ue_ip_t *ipv6;
|
ogs_pfcp_ue_ip_t *ipv6;
|
||||||
|
|
||||||
|
ogs_ipsubnet_t *ipv4_framed_routes;
|
||||||
|
ogs_ipsubnet_t *ipv6_framed_routes;
|
||||||
|
|
||||||
char *gx_sid; /* Gx Session ID */
|
char *gx_sid; /* Gx Session ID */
|
||||||
ogs_pfcp_node_t *pfcp_node;
|
ogs_pfcp_node_t *pfcp_node;
|
||||||
|
|
||||||
|
@ -126,6 +140,10 @@ upf_sess_t *upf_sess_find_by_ipv6(uint32_t *addr6);
|
||||||
|
|
||||||
uint8_t upf_sess_set_ue_ip(upf_sess_t *sess,
|
uint8_t upf_sess_set_ue_ip(upf_sess_t *sess,
|
||||||
uint8_t session_type, ogs_pfcp_pdr_t *pdr);
|
uint8_t session_type, ogs_pfcp_pdr_t *pdr);
|
||||||
|
uint8_t upf_sess_set_ue_ipv4_framed_routes(upf_sess_t *sess,
|
||||||
|
char *framed_routes[]);
|
||||||
|
uint8_t upf_sess_set_ue_ipv6_framed_routes(upf_sess_t *sess,
|
||||||
|
char *framed_routes[]);
|
||||||
|
|
||||||
void upf_sess_urr_acc_add(upf_sess_t *sess, ogs_pfcp_urr_t *urr, size_t size, bool is_uplink);
|
void upf_sess_urr_acc_add(upf_sess_t *sess, ogs_pfcp_urr_t *urr, size_t size, bool is_uplink);
|
||||||
void upf_sess_urr_acc_fill_usage_report(upf_sess_t *sess, const ogs_pfcp_urr_t *urr,
|
void upf_sess_urr_acc_fill_usage_report(upf_sess_t *sess, const ogs_pfcp_urr_t *urr,
|
||||||
|
|
|
@ -61,6 +61,36 @@ static ogs_pkbuf_pool_t *packet_pool = NULL;
|
||||||
|
|
||||||
static void upf_gtp_handle_multicast(ogs_pkbuf_t *recvbuf);
|
static void upf_gtp_handle_multicast(ogs_pkbuf_t *recvbuf);
|
||||||
|
|
||||||
|
static int check_framed_routes(upf_sess_t *sess, int family, uint32_t *addr)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
ogs_ipsubnet_t *routes = family == AF_INET ?
|
||||||
|
sess->ipv4_framed_routes : sess->ipv6_framed_routes;
|
||||||
|
|
||||||
|
if (!routes)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (i = 0; i < OGS_MAX_NUM_OF_FRAMED_ROUTES_IN_PDI; i++) {
|
||||||
|
uint32_t *sub = routes[i].sub;
|
||||||
|
uint32_t *mask = routes[i].mask;
|
||||||
|
|
||||||
|
if (!routes[i].family)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (family == AF_INET) {
|
||||||
|
if (sub[0] == (addr[0] & mask[0]))
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if (sub[0] == (addr[0] & mask[0]) &&
|
||||||
|
sub[1] == (addr[1] & mask[1]) &&
|
||||||
|
sub[2] == (addr[2] & mask[2]) &&
|
||||||
|
sub[3] == (addr[3] & mask[3]))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static uint16_t _get_eth_type(uint8_t *data, uint len) {
|
static uint16_t _get_eth_type(uint8_t *data, uint len) {
|
||||||
if (len > ETHER_HDR_LEN) {
|
if (len > ETHER_HDR_LEN) {
|
||||||
struct ether_header *hdr = (struct ether_header*)data;
|
struct ether_header *hdr = (struct ether_header*)data;
|
||||||
|
@ -443,6 +473,8 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
|
||||||
|
|
||||||
if (src_addr[0] == sess->ipv4->addr[0]) {
|
if (src_addr[0] == sess->ipv4->addr[0]) {
|
||||||
/* Source IP address should be matched in uplink */
|
/* Source IP address should be matched in uplink */
|
||||||
|
} else if (check_framed_routes(sess, AF_INET, src_addr)) {
|
||||||
|
/* Or source IP address should match a framed route */
|
||||||
} else {
|
} else {
|
||||||
ogs_error("[DROP] Source IP-%d Spoofing APN:%s SrcIf:%d DstIf:%d TEID:0x%x",
|
ogs_error("[DROP] Source IP-%d Spoofing APN:%s SrcIf:%d DstIf:%d TEID:0x%x",
|
||||||
ip_h->ip_v, pdr->dnn, pdr->src_if, far->dst_if, teid);
|
ip_h->ip_v, pdr->dnn, pdr->src_if, far->dst_if, teid);
|
||||||
|
@ -519,6 +551,8 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
|
||||||
* If Global address
|
* If Global address
|
||||||
* 64 bit prefix should be matched
|
* 64 bit prefix should be matched
|
||||||
*/
|
*/
|
||||||
|
} else if (check_framed_routes(sess, AF_INET6, src_addr)) {
|
||||||
|
/* Or source IP address should match a framed route */
|
||||||
} else {
|
} else {
|
||||||
ogs_error("[DROP] Source IP-%d Spoofing APN:%s SrcIf:%d DstIf:%d TEID:0x%x",
|
ogs_error("[DROP] Source IP-%d Spoofing APN:%s SrcIf:%d DstIf:%d TEID:0x%x",
|
||||||
ip_h->ip_v, pdr->dnn, pdr->src_if, far->dst_if, teid);
|
ip_h->ip_v, pdr->dnn, pdr->src_if, far->dst_if, teid);
|
||||||
|
|
|
@ -138,6 +138,22 @@ void upf_n4_handle_session_establishment_request(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pdr->ipv4_framed_routes) {
|
||||||
|
cause_value =
|
||||||
|
upf_sess_set_ue_ipv4_framed_routes(sess,
|
||||||
|
pdr->ipv4_framed_routes);
|
||||||
|
if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED)
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pdr->ipv6_framed_routes) {
|
||||||
|
cause_value =
|
||||||
|
upf_sess_set_ue_ipv6_framed_routes(sess,
|
||||||
|
pdr->ipv6_framed_routes);
|
||||||
|
if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED)
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
/* Setup UPF-N3-TEID & QFI Hash */
|
/* Setup UPF-N3-TEID & QFI Hash */
|
||||||
if (pdr->f_teid_len) {
|
if (pdr->f_teid_len) {
|
||||||
ogs_pfcp_object_type_e type = OGS_PFCP_OBJ_SESS_TYPE;
|
ogs_pfcp_object_type_e type = OGS_PFCP_OBJ_SESS_TYPE;
|
||||||
|
|
Loading…
Reference in New Issue