neels has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-upf/+/31485 )
Change subject: scale: faster lookup whether local TEID is in use ......................................................................
scale: faster lookup whether local TEID is in use
Keep a hash table of all local GTP TEID assigned: speed up handing out new TEID to new GTP tunnels, for both tunend and tunmap.
Before this, whenever osmo-upf sets up a tunnel, it would have to linearly iterate *all* peers x sessions x GTP tunnels to ensure that a TEID is not already in use. Now we iterate only one hashtable bucket.
Scoping: technically, a TEID would be scoped by the local GTP IP address. For simplicity, osmo-upf hands out each TEID only once, across all local GTP IP addresses. This also helps when analysing pcaps.
Change-Id: I920bb14da434ac29fcd49d95d207081bacb3d661 --- 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, 35 insertions(+), 24 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-upf refs/changes/85/31485/1
diff --git a/include/osmocom/upf/up_session.h b/include/osmocom/upf/up_session.h index c424df9..d42254d 100644 --- a/include/osmocom/upf/up_session.h +++ b/include/osmocom/upf/up_session.h @@ -69,7 +69,7 @@ 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); +struct up_session *up_session_find_by_local_teid(uint32_t teid);
void up_session_set_msg_ctx(struct up_session *session, struct osmo_pfcp_msg *m);
@@ -101,6 +101,9 @@ bool active;
char *inactive_reason; + + /* hashtable entry for g_upf->pdr_by_local_teid */ + struct hlist_node node_by_local_teid; };
int pdr_to_str_buf(char *buf, size_t buflen, const struct pdr *pdr); diff --git a/include/osmocom/upf/upf.h b/include/osmocom/upf/upf.h index 0d43785..acf28e3 100644 --- a/include/osmocom/upf/upf.h +++ b/include/osmocom/upf/upf.h @@ -121,6 +121,7 @@
struct { uint32_t next_local_teid_state; + DECLARE_HASHTABLE(pdr_by_local_teid, 6); } gtp;
struct llist_head netinst; diff --git a/src/osmo-upf/up_session.c b/src/osmo-upf/up_session.c index 593f131..4700675 100644 --- a/src/osmo-upf/up_session.c +++ b/src/osmo-upf/up_session.c @@ -377,6 +377,8 @@ static void pdr_del(struct pdr *pdr) { llist_del(&pdr->entry); + if (pdr->local_f_teid) + hlist_del(&pdr->node_by_local_teid); talloc_free(pdr); }
@@ -479,6 +481,7 @@ .local_f_teid_present = true, .local_f_teid = *pdr->local_f_teid, }; + hash_add(g_upf->gtp.pdr_by_local_teid, &pdr->node_by_local_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, @@ -1052,18 +1055,12 @@ return NULL; }
-struct up_session *up_session_find_by_local_teid(struct up_peer *peer, uint32_t teid) +struct up_session *up_session_find_by_local_teid(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; - } + struct pdr *pdr; + hash_for_each_possible(g_upf->gtp.pdr_by_local_teid, pdr, node_by_local_teid, teid) { + if (pdr->local_f_teid && teid == pdr->local_f_teid->fixed.teid) + return pdr->session; } return NULL; } diff --git a/src/osmo-upf/upf.c b/src/osmo-upf/upf.c index 1e5e549..43b379c 100644 --- a/src/osmo-upf/upf.c +++ b/src/osmo-upf/upf.c @@ -68,6 +68,7 @@ INIT_LLIST_HEAD(&g_upf->netinst);
hash_init(g_upf->tunmap.nft_tun_by_chain_id); + hash_init(g_upf->gtp.pdr_by_local_teid); }
int upf_pfcp_init(void) @@ -122,17 +123,6 @@ return 0; }
-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; - } - return false; -} - static uint32_t upf_next_local_teid_inc(void) { g_upf->gtp.next_local_teid_state++; @@ -146,7 +136,7 @@ uint32_t sanity; for (sanity = 2342; sanity; sanity--) { uint32_t next_teid = upf_next_local_teid_inc(); - if (upf_is_local_teid_in_use(next_teid)) + if (up_session_find_by_local_teid(next_teid)) continue; return next_teid; }