mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-upf.git
synced 2025-10-23 00:02:03 +00:00
Introduce hashtable to lookup chain_id
This lookup was taking ages specially when UPF already managed thousands of sessions. Related: SYS#6398 Change-Id: I7df8fd945eedbda98bd08e9fb2f382e0f55c2983
This commit is contained in:
@@ -64,6 +64,9 @@ struct up_gtp_action {
|
||||
void *handle;
|
||||
};
|
||||
|
||||
struct up_gtp_action *up_gtp_action_alloc(void *ctx, struct up_session *session, enum up_gtp_action_kind kind, struct llist_head *dst);
|
||||
void up_gtp_action_free(struct up_gtp_action *a);
|
||||
|
||||
int up_gtp_action_cmp(const struct up_gtp_action *a, const struct up_gtp_action *b);
|
||||
|
||||
int up_gtp_action_enable(struct up_gtp_action *a);
|
||||
|
@@ -115,6 +115,8 @@ struct g_upf {
|
||||
int priority_pre;
|
||||
int priority_post;
|
||||
uint32_t next_chain_id_state;
|
||||
/* hashtable of (struct upf_nft_tun)->node_by_chain_id: */
|
||||
DECLARE_HASHTABLE(nft_tun_by_chain_id, 10);
|
||||
} tunmap;
|
||||
|
||||
struct {
|
||||
|
@@ -24,10 +24,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <osmocom/core/hashtable.h>
|
||||
|
||||
#include <osmocom/upf/upf_tun.h>
|
||||
|
||||
struct upf_nft_tun {
|
||||
struct hlist_node node_by_chain_id; /* item in g_upf->tunmap.nft_tun_by_chain_id */
|
||||
struct upf_tun tun;
|
||||
uint32_t chain_id;
|
||||
};
|
||||
|
@@ -198,3 +198,33 @@ char *up_gtp_action_to_str_c(void *ctx, const struct up_gtp_action *a)
|
||||
{
|
||||
OSMO_NAME_C_IMPL(ctx, 128, "ERROR", up_gtp_action_to_str_buf, a)
|
||||
}
|
||||
|
||||
struct up_gtp_action *up_gtp_action_alloc(void *ctx, struct up_session *session, enum up_gtp_action_kind kind, struct llist_head *dst)
|
||||
{
|
||||
struct up_gtp_action *a = talloc_zero(ctx, struct up_gtp_action);
|
||||
OSMO_ASSERT(a);
|
||||
a->session = session;
|
||||
a->kind = kind;
|
||||
|
||||
if (kind == UP_GTP_U_TUNMAP) {
|
||||
INIT_HLIST_NODE(&a->tunmap.access.node_by_chain_id);
|
||||
INIT_HLIST_NODE(&a->tunmap.core.node_by_chain_id);
|
||||
}
|
||||
llist_add_tail(&a->entry, dst);
|
||||
return a;
|
||||
}
|
||||
|
||||
void up_gtp_action_free(struct up_gtp_action *a)
|
||||
{
|
||||
if (!a)
|
||||
return;
|
||||
up_gtp_action_disable(a);
|
||||
llist_del(&a->entry);
|
||||
if (a->kind == UP_GTP_U_TUNMAP) {
|
||||
if (!hlist_unhashed(&a->tunmap.access.node_by_chain_id))
|
||||
hash_del(&a->tunmap.access.node_by_chain_id);
|
||||
if (!hlist_unhashed(&a->tunmap.core.node_by_chain_id))
|
||||
hash_del(&a->tunmap.core.node_by_chain_id);
|
||||
}
|
||||
talloc_free(a);
|
||||
}
|
||||
|
@@ -824,9 +824,7 @@ static void up_session_established_onleave(struct osmo_fsm_inst *fi, uint32_t ne
|
||||
|
||||
/* Shut down all active GTP rules */
|
||||
while ((a = llist_first_entry_or_null(&session->active_gtp_actions, struct up_gtp_action, entry))) {
|
||||
up_gtp_action_disable(a);
|
||||
llist_del(&a->entry);
|
||||
talloc_free(a);
|
||||
up_gtp_action_free(a);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1202,31 +1200,14 @@ static void add_gtp_action_tunend(void *ctx, struct llist_head *dst, struct pdr
|
||||
talloc_free(rpdr->inactive_reason);
|
||||
rpdr->inactive_reason = NULL;
|
||||
|
||||
a = talloc(ctx, struct up_gtp_action);
|
||||
OSMO_ASSERT(a);
|
||||
*a = (struct up_gtp_action){
|
||||
.session = session,
|
||||
.pdr_access = pdr->desc.pdr_id,
|
||||
.pdr_core = rpdr->desc.pdr_id,
|
||||
.kind = UP_GTP_U_TUNEND,
|
||||
.tunend = {
|
||||
.access = {
|
||||
.local = {
|
||||
.addr = pdr->local_f_teid->fixed.ip_addr.v4,
|
||||
.teid = pdr->local_f_teid->fixed.teid,
|
||||
},
|
||||
.remote = {
|
||||
.addr = rfar_forw->outer_header_creation.ip_addr.v4,
|
||||
.teid = rfar_forw->outer_header_creation.teid,
|
||||
},
|
||||
},
|
||||
.core = {
|
||||
.ue_local_addr = rpdr->desc.pdi.ue_ip_address.ip_addr.v4,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
llist_add_tail(&a->entry, dst);
|
||||
a = up_gtp_action_alloc(ctx, session, UP_GTP_U_TUNEND, dst);
|
||||
a->pdr_access = pdr->desc.pdr_id;
|
||||
a->pdr_core = rpdr->desc.pdr_id;
|
||||
a->tunend.access.local.addr = pdr->local_f_teid->fixed.ip_addr.v4;
|
||||
a->tunend.access.local.teid = pdr->local_f_teid->fixed.teid;
|
||||
a->tunend.access.remote.addr = rfar_forw->outer_header_creation.ip_addr.v4;
|
||||
a->tunend.access.remote.teid = rfar_forw->outer_header_creation.teid;
|
||||
a->tunend.core.ue_local_addr = rpdr->desc.pdi.ue_ip_address.ip_addr.v4;
|
||||
}
|
||||
|
||||
/* A GTP tunnel on Access side, mapping to another GTP tunnel on Core side and vice versa.
|
||||
@@ -1316,38 +1297,17 @@ static void add_gtp_action_tunmap(void *ctx, struct llist_head *dst, struct pdr
|
||||
talloc_free(rpdr->inactive_reason);
|
||||
rpdr->inactive_reason = NULL;
|
||||
|
||||
a = talloc(ctx, struct up_gtp_action);
|
||||
OSMO_ASSERT(a);
|
||||
*a = (struct up_gtp_action){
|
||||
.session = session,
|
||||
.pdr_access = pdr->desc.pdr_id,
|
||||
.pdr_core = rpdr->desc.pdr_id,
|
||||
.kind = UP_GTP_U_TUNMAP,
|
||||
.tunmap = {
|
||||
.access.tun = {
|
||||
.local = {
|
||||
.addr = pdr->local_f_teid->fixed.ip_addr.v4,
|
||||
.teid = pdr->local_f_teid->fixed.teid,
|
||||
},
|
||||
.remote = {
|
||||
.addr = rfar_forw->outer_header_creation.ip_addr.v4,
|
||||
.teid = rfar_forw->outer_header_creation.teid,
|
||||
},
|
||||
},
|
||||
.core.tun = {
|
||||
.local = {
|
||||
.addr = rpdr->local_f_teid->fixed.ip_addr.v4,
|
||||
.teid = rpdr->local_f_teid->fixed.teid,
|
||||
},
|
||||
.remote = {
|
||||
.addr = far_forw->outer_header_creation.ip_addr.v4,
|
||||
.teid = far_forw->outer_header_creation.teid,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
llist_add_tail(&a->entry, dst);
|
||||
a = up_gtp_action_alloc(ctx, session, UP_GTP_U_TUNMAP, dst);
|
||||
a->pdr_access = pdr->desc.pdr_id;
|
||||
a->pdr_core = rpdr->desc.pdr_id;
|
||||
a->tunmap.access.tun.local.addr = pdr->local_f_teid->fixed.ip_addr.v4;
|
||||
a->tunmap.access.tun.local.teid = pdr->local_f_teid->fixed.teid;
|
||||
a->tunmap.access.tun.remote.addr = rfar_forw->outer_header_creation.ip_addr.v4;
|
||||
a->tunmap.access.tun.remote.teid = rfar_forw->outer_header_creation.teid;
|
||||
a->tunmap.core.tun.local.addr = rpdr->local_f_teid->fixed.ip_addr.v4;
|
||||
a->tunmap.core.tun.local.teid = rpdr->local_f_teid->fixed.teid;
|
||||
a->tunmap.core.tun.remote.addr = far_forw->outer_header_creation.ip_addr.v4;
|
||||
a->tunmap.core.tun.remote.teid = far_forw->outer_header_creation.teid;
|
||||
}
|
||||
|
||||
/* Analyse all PDRs and FARs and find configurations that match either a GTP encaps/decaps or a GTP forward rule. Add to
|
||||
@@ -1472,9 +1432,7 @@ static enum osmo_pfcp_cause setup_gtp_actions(struct up_session *session, struct
|
||||
continue;
|
||||
|
||||
LOGPFSML(session->fi, LOGL_DEBUG, "disabling: %s\n", up_gtp_action_to_str_c(OTC_SELECT, a));
|
||||
up_gtp_action_disable(a);
|
||||
llist_del(&a->entry);
|
||||
talloc_free(a);
|
||||
up_gtp_action_free(a);
|
||||
}
|
||||
|
||||
/* Set up all GTP tunnels requested in the session setup, but not active yet */
|
||||
|
@@ -78,6 +78,7 @@ void g_upf_alloc(void *ctx)
|
||||
INIT_LLIST_HEAD(&g_upf->tunend.vty_cfg.devs);
|
||||
INIT_LLIST_HEAD(&g_upf->tunend.devs);
|
||||
INIT_LLIST_HEAD(&g_upf->netinst);
|
||||
hash_init(g_upf->tunmap.nft_tun_by_chain_id);
|
||||
hash_init(g_upf->gtp.pdrs_by_local_f_teid);
|
||||
}
|
||||
|
||||
@@ -175,6 +176,17 @@ static uint32_t upf_next_chain_id_inc(void)
|
||||
return g_upf->tunmap.next_chain_id_state;
|
||||
}
|
||||
|
||||
static bool upf_is_chain_id_in_use(uint32_t chain_id)
|
||||
{
|
||||
struct upf_nft_tun *nft_tun;
|
||||
hash_for_each_possible(g_upf->tunmap.nft_tun_by_chain_id, nft_tun, node_by_chain_id, chain_id) {
|
||||
if (nft_tun->chain_id != chain_id)
|
||||
continue;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Return an unused chain_id, or 0 if none is found with sane effort. */
|
||||
uint32_t upf_next_chain_id(void)
|
||||
{
|
||||
@@ -182,36 +194,14 @@ uint32_t upf_next_chain_id(void)
|
||||
|
||||
/* Make sure the new chain_id is not used anywhere */
|
||||
for (sanity = 2342; sanity; sanity--) {
|
||||
struct up_peer *peer;
|
||||
uint32_t chain_id = upf_next_chain_id_inc();
|
||||
bool taken = false;
|
||||
|
||||
if (!g_upf->pfcp.ep)
|
||||
return chain_id;
|
||||
|
||||
llist_for_each_entry(peer, &g_upf->pfcp.ep->peers, entry) {
|
||||
struct up_session *session;
|
||||
int bkt;
|
||||
hash_for_each(peer->sessions_by_up_seid, bkt, session, node_by_up_seid) {
|
||||
struct up_gtp_action *a;
|
||||
llist_for_each_entry(a, &session->active_gtp_actions, entry) {
|
||||
if (a->kind != UP_GTP_U_TUNMAP)
|
||||
continue;
|
||||
if (a->tunmap.access.chain_id == chain_id
|
||||
|| a->tunmap.core.chain_id == chain_id) {
|
||||
taken = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (taken)
|
||||
break;
|
||||
}
|
||||
if (taken)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!taken)
|
||||
return chain_id;
|
||||
if (upf_is_chain_id_in_use(chain_id))
|
||||
continue;
|
||||
return chain_id;
|
||||
}
|
||||
|
||||
/* finding a chain_id became insane, return invalid = 0 */
|
||||
|
@@ -489,6 +489,7 @@ static int upf_nft_tunmap_ensure_chain_id(struct upf_nft_tun *tun)
|
||||
tun->chain_id = upf_next_chain_id();
|
||||
if (!tun->chain_id)
|
||||
return -ENOSPC;
|
||||
hash_add(g_upf->tunmap.nft_tun_by_chain_id, &tun->node_by_chain_id, tun->chain_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user