Introduce hashtable to look up gtp_tundev by local TEID

Use this hashtable while looking up for tunend based on
<access.local.teid, access.remote.teid, access.remote.addr>.
This kind of look up is used every time a session is added or removed,
which means potentially thousands of tunend sessions were being iterated
linerarly every time.

For simplification (easier/quicker hashtable key generation), reduce the
whole key presented above to a more general one based on
"access.local.teid". This is usually enough since we are anyways
allocating local TEIDs globally per tunnel without caring about remote
address.

Change-Id: Ib12ecc8ce87175071c52c0ed2217a29d901f0f05
This commit is contained in:
Pau Espin Pedrol
2025-02-17 19:12:44 +01:00
parent bede7f130f
commit b6d689d677
2 changed files with 10 additions and 2 deletions

View File

@@ -24,6 +24,7 @@
#pragma once #pragma once
#include <osmocom/core/linuxlist.h> #include <osmocom/core/linuxlist.h>
#include <osmocom/core/hashtable.h>
#include <osmocom/core/select.h> #include <osmocom/core/select.h>
#include <osmocom/core/logging.h> #include <osmocom/core/logging.h>
@@ -55,6 +56,8 @@ struct upf_gtp_dev {
/* list of struct upf_gtp_tunend */ /* list of struct upf_gtp_tunend */
struct llist_head tunnels; struct llist_head tunnels;
/* hashtable of (struct upf_gtp_tunen) with key desc.access.local.teid */
DECLARE_HASHTABLE(tunnels_by_local_f_teid, 10);
}; };
/* Description of a GTP encapsulation / decapsulation. /* Description of a GTP encapsulation / decapsulation.

View File

@@ -134,6 +134,7 @@ static struct upf_gtp_dev *upf_gtp_dev_alloc(const char *name, const char *local
.gtpv1.ofd.fd = -1, .gtpv1.ofd.fd = -1,
}; };
INIT_LLIST_HEAD(&dev->tunnels); INIT_LLIST_HEAD(&dev->tunnels);
hash_init(dev->tunnels_by_local_f_teid);
osmo_sockaddr_str_from_str(&addr_conv, local_addr, PORT_GTP0_U); osmo_sockaddr_str_from_str(&addr_conv, local_addr, PORT_GTP0_U);
@@ -318,7 +319,8 @@ int upf_gtp_genl_ensure_open()
} }
struct upf_gtp_tunend { struct upf_gtp_tunend {
struct llist_head entry; struct llist_head entry; /* item in (struct upf_gtp_dev)->tunnels */
struct hlist_node node_by_local_f_teid; /* item in g_upf->gtp.pdrs_by_local_f_teid */
struct upf_gtp_dev *dev; struct upf_gtp_dev *dev;
struct upf_tunend desc; struct upf_tunend desc;
@@ -349,6 +351,7 @@ static int upf_gtp_tunend_destruct(struct upf_gtp_tunend *tun)
{ {
if (tun->active) if (tun->active)
upf_gtp_tunend_deactivate(tun); upf_gtp_tunend_deactivate(tun);
hash_del(&tun->node_by_local_f_teid);
llist_del(&tun->entry); llist_del(&tun->entry);
return 0; return 0;
} }
@@ -369,6 +372,7 @@ static struct upf_gtp_tunend *upf_gtp_tunend_alloc(struct upf_gtp_dev *dev, cons
.dev = dev, .dev = dev,
.desc = *desc, .desc = *desc,
}; };
hash_add(dev->tunnels_by_local_f_teid, &tun->node_by_local_f_teid, tun->desc.access.local.teid);
llist_add(&tun->entry, &dev->tunnels); llist_add(&tun->entry, &dev->tunnels);
talloc_set_destructor(tun, upf_gtp_tunend_destruct); talloc_set_destructor(tun, upf_gtp_tunend_destruct);
return tun; return tun;
@@ -425,7 +429,8 @@ static struct upf_gtp_tunend *upf_gtp_dev_tunend_find(struct upf_gtp_dev *dev, c
{ {
struct upf_gtp_tunend *tun; struct upf_gtp_tunend *tun;
tunend_validate(tunend); tunend_validate(tunend);
llist_for_each_entry(tun, &dev->tunnels, entry) {
hash_for_each_possible(dev->tunnels_by_local_f_teid, tun, node_by_local_f_teid, tunend->access.local.teid) {
if (upf_gtp_tunend_cmp(tunend, &tun->desc)) if (upf_gtp_tunend_cmp(tunend, &tun->desc))
continue; continue;
return tun; return tun;