pespin has submitted this change. ( https://gerrit.osmocom.org/c/osmo-upf/+/39451?usp=email )
Change subject: Introduce hashtable to lookup session by F-TEID ......................................................................
Introduce hashtable to lookup session by F-TEID
This is a hot path when creating new sessions. Previous code would take ages specially when UPF already had thousands of sessions created and a new TEID to allocate was being looked up.
Related: SYS#6398 Change-Id: I90ecbb07b242c1de2298261019f24aa5f5810fda --- M include/osmocom/upf/up_session.h M include/osmocom/upf/upf.h M src/osmo-upf/up_session.c M src/osmo-upf/upf.c 4 files changed, 17 insertions(+), 23 deletions(-)
Approvals: fixeria: Looks good to me, but someone else must approve laforge: Looks good to me, but someone else must approve pespin: Looks good to me, approved Jenkins Builder: Verified
diff --git a/include/osmocom/upf/up_session.h b/include/osmocom/upf/up_session.h index c424df9..3dc7bb1 100644 --- a/include/osmocom/upf/up_session.h +++ b/include/osmocom/upf/up_session.h @@ -69,7 +69,6 @@ struct up_session *up_session_find_or_add(struct up_peer *peer, const struct osmo_pfcp_ie_f_seid *cp_f_seid); struct up_session *up_session_find_by_up_seid(struct up_peer *peer, uint64_t up_seid); struct up_session *up_session_find_by_cp_f_seid(struct up_peer *peer, const struct osmo_pfcp_ie_f_seid *cp_f_seid); -struct up_session *up_session_find_by_local_teid(struct up_peer *peer, uint32_t teid);
void up_session_set_msg_ctx(struct up_session *session, struct osmo_pfcp_msg *m);
@@ -83,7 +82,8 @@ char *up_session_to_str_c(void *ctx, struct up_session *session);
struct pdr { - struct llist_head entry; + struct llist_head entry; /* item in session->pdrs */ + struct hlist_node node_by_local_f_teid; /* item in g_upf->gtp.pdrs_by_local_f_teid */ struct up_session *session;
struct osmo_pfcp_ie_create_pdr desc; diff --git a/include/osmocom/upf/upf.h b/include/osmocom/upf/upf.h index d558600..0e5406f 100644 --- a/include/osmocom/upf/upf.h +++ b/include/osmocom/upf/upf.h @@ -28,6 +28,7 @@ #include <osmocom/core/socket.h> #include <osmocom/core/select.h> #include <osmocom/core/linuxlist.h> +#include <osmocom/core/hashtable.h>
struct osmo_tdef; struct ctrl_handle; @@ -118,6 +119,8 @@
struct { uint32_t next_local_teid_state; + /* hashtable of (struct pdr)->node_by_local_f_teid: */ + DECLARE_HASHTABLE(pdrs_by_local_f_teid, 10); uint16_t next_echo_seq_nr; } gtp;
diff --git a/src/osmo-upf/up_session.c b/src/osmo-upf/up_session.c index 198bf88..359d116 100644 --- a/src/osmo-upf/up_session.c +++ b/src/osmo-upf/up_session.c @@ -379,6 +379,8 @@
static void pdr_del(struct pdr *pdr) { + if (!hlist_unhashed(&pdr->node_by_local_f_teid)) + hash_del(&pdr->node_by_local_f_teid); llist_del(&pdr->entry); talloc_free(pdr); } @@ -411,6 +413,7 @@ .session = session, .desc = *create_pdr, }; + INIT_HLIST_NODE(&pdr->node_by_local_f_teid); llist_add_tail(&pdr->entry, &session->pdrs);
if (pdr->desc.far_id_present) { @@ -482,6 +485,7 @@ .local_f_teid_present = true, .local_f_teid = *pdr->local_f_teid, }; + hash_add(g_upf->gtp.pdrs_by_local_f_teid, &pdr->node_by_local_f_teid, pdr->local_f_teid->fixed.teid); } else { created_pdr[*created_pdr_count] = (struct osmo_pfcp_ie_created_pdr){ .pdr_id = pdr->desc.pdr_id, @@ -1054,22 +1058,6 @@ return NULL; }
-struct up_session *up_session_find_by_local_teid(struct up_peer *peer, uint32_t teid) -{ - struct up_session *session; - int bkt; - hash_for_each(peer->sessions_by_up_seid, bkt, session, node_by_up_seid) { - struct pdr *pdr; - llist_for_each_entry(pdr, &session->pdrs, entry) { - if (!pdr->local_f_teid) - continue; - if (pdr->local_f_teid->fixed.teid == teid) - return session; - } - } - return NULL; -} - static bool action_is_forw(const struct osmo_pfcp_ie_apply_action *aa) { return osmo_pfcp_bits_get(aa->bits, OSMO_PFCP_APPLY_ACTION_FORW) diff --git a/src/osmo-upf/upf.c b/src/osmo-upf/upf.c index a4cb79b..c82227d 100644 --- a/src/osmo-upf/upf.c +++ b/src/osmo-upf/upf.c @@ -78,6 +78,7 @@ 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->gtp.pdrs_by_local_f_teid); }
int upf_pfcp_init(void) @@ -135,11 +136,13 @@
static bool upf_is_local_teid_in_use(uint32_t teid) { - struct up_peer *peer; - llist_for_each_entry(peer, &g_upf->pfcp.ep->peers, entry) { - struct up_session *session = up_session_find_by_local_teid(peer, teid); - if (session) - return true; + struct pdr *pdr; + hash_for_each_possible(g_upf->gtp.pdrs_by_local_f_teid, pdr, node_by_local_f_teid, teid) { + if (!pdr->local_f_teid) + continue; + if (pdr->local_f_teid->fixed.teid != teid) + continue; + return true; } return false; }