This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.
daniel gerrit-no-reply at lists.osmocom.orgdaniel has submitted this change. ( https://gerrit.osmocom.org/c/osmo-sgsn/+/22251 ) Change subject: gbproxy: Implement IMSI cache ...................................................................... gbproxy: Implement IMSI cache When SGSN pooling is enabled we need to route some responses based on IMSI back to the correct SGSN, e.g. PAGING_PS_REJECT. The IMSI cache keeps track of this IMSI <-> NSE(SGSN) mapping. Change-Id: If0a8d6cc1d63f2fb2c395cc5d4373a915bc2cb87 Related: OS#4951, OS#4472 --- M include/osmocom/sgsn/gb_proxy.h M src/gbproxy/gb_proxy.c M src/gbproxy/gb_proxy_peer.c 3 files changed, 153 insertions(+), 2 deletions(-) Approvals: Jenkins Builder: Verified laforge: Looks good to me, but someone else must approve lynxis lazus: Looks good to me, approved diff --git a/include/osmocom/sgsn/gb_proxy.h b/include/osmocom/sgsn/gb_proxy.h index 04a3c4b..d988cae 100644 --- a/include/osmocom/sgsn/gb_proxy.h +++ b/include/osmocom/sgsn/gb_proxy.h @@ -8,6 +8,7 @@ #include <osmocom/core/hashtable.h> #include <osmocom/gsm/gsm23003.h> #include <osmocom/gsm/gsm23236.h> +#include <osmocom/gsm/protocol/gsm_23_003.h> #include <osmocom/gprs/gprs_ns2.h> #include <osmocom/vty/command.h> @@ -83,6 +84,14 @@ uint8_t timeout; } tlli_cache; + /* imsi<->nse cache used for PAGING REJECT */ + struct { + DECLARE_HASHTABLE(entries, 10); + struct osmo_timer_list timer; + /* Time in seconds that the entries should be valid */ + uint8_t timeout; + } imsi_cache; + /* List of all SGSNs */ struct llist_head sgsns; @@ -173,7 +182,7 @@ /* TLLI cache */ struct gbproxy_tlli_cache_entry { - /* linked to gbproxy_config.tlli_cache */ + /* linked to gbproxy_config.tlli_cache.entries */ struct hlist_node list; /* TLLI of the entry */ @@ -184,6 +193,19 @@ struct gbproxy_nse *nse; }; +/* IMSI cache */ +struct gbproxy_imsi_cache_entry { + /* linked to gbproxy_config.imsi_cache.entries */ + struct hlist_node list; + + /* IMSI of the entry */ + char imsi[OSMO_IMSI_BUF_SIZE]; + /* When was this entry last seen */ + time_t tstamp; + /* The SGSN where the request came from */ + struct gbproxy_nse *nse; +}; + /* Convenience logging macros for NSE/BVC */ #define LOGPNSE_CAT(NSE, SUBSYS, LEVEL, FMT, ARGS...) \ LOGP(SUBSYS, LEVEL, "NSE(%05u/%s) " FMT, (NSE)->nsei, \ @@ -251,12 +273,18 @@ struct gbproxy_nse *gbproxy_nse_by_nsei(struct gbproxy_config *cfg, uint16_t nsei, uint32_t flags); struct gbproxy_nse *gbproxy_nse_by_nsei_or_new(struct gbproxy_config *cfg, uint16_t nsei, bool sgsn_facing); struct gbproxy_nse *gbproxy_nse_by_tlli(struct gbproxy_config *cfg, uint32_t tlli); +struct gbproxy_nse *gbproxy_nse_by_imsi(struct gbproxy_config *cfg, const char *imsi); /* TLLI cache */ void gbproxy_tlli_cache_update(struct gbproxy_nse *nse, uint32_t tlli); void gbproxy_tlli_cache_remove(struct gbproxy_config *cfg, uint32_t tlli); int gbproxy_tlli_cache_cleanup(struct gbproxy_config *cfg); +/* IMSI cache */ +void gbproxy_imsi_cache_update(struct gbproxy_nse *nse, const char *imsi); +void gbproxy_imsi_cache_remove(struct gbproxy_config *cfg, const char *imsi); +int gbproxy_imsi_cache_cleanup(struct gbproxy_config *cfg); + /* SGSN handling */ struct gbproxy_sgsn *gbproxy_sgsn_alloc(struct gbproxy_config *cfg, uint16_t nsei, const char *name); void gbproxy_sgsn_free(struct gbproxy_sgsn *sgsn); diff --git a/src/gbproxy/gb_proxy.c b/src/gbproxy/gb_proxy.c index 7f8260c..d8bca58 100644 --- a/src/gbproxy/gb_proxy.c +++ b/src/gbproxy/gb_proxy.c @@ -1405,6 +1405,15 @@ osmo_timer_schedule(&cfg->tlli_cache.timer, 2, 0); } +static void imsi_cache_cleanup(void *data) +{ + struct gbproxy_config *cfg = data; + gbproxy_imsi_cache_cleanup(cfg); + + /* TODO: Disable timer when cache is empty */ + osmo_timer_schedule(&cfg->imsi_cache.timer, 2, 0); +} + int gbproxy_init_config(struct gbproxy_config *cfg) { struct timespec tp; @@ -1414,6 +1423,7 @@ cfg->pool.null_nri_ranges = osmo_nri_ranges_alloc(cfg); /* TODO: Make configurable */ cfg->tlli_cache.timeout = 10; + cfg->imsi_cache.timeout = 10; hash_init(cfg->bss_nses); hash_init(cfg->sgsn_nses); @@ -1424,6 +1434,10 @@ osmo_timer_setup(&cfg->tlli_cache.timer, tlli_cache_cleanup, cfg); osmo_timer_schedule(&cfg->tlli_cache.timer, 2, 0); + /* We could also combine both timers */ + osmo_timer_setup(&cfg->imsi_cache.timer, imsi_cache_cleanup, cfg); + osmo_timer_schedule(&cfg->imsi_cache.timer, 2, 0); + cfg->ctrg = rate_ctr_group_alloc(tall_sgsn_ctx, &global_ctrg_desc, 0); if (!cfg->ctrg) { LOGP(DGPRS, LOGL_ERROR, "Cannot allocate global counter group!\n"); diff --git a/src/gbproxy/gb_proxy_peer.c b/src/gbproxy/gb_proxy_peer.c index 104902b..1d9352d 100644 --- a/src/gbproxy/gb_proxy_peer.c +++ b/src/gbproxy/gb_proxy_peer.c @@ -25,11 +25,13 @@ #include <osmocom/sgsn/debug.h> #include <osmocom/gprs/protocol/gsm_08_18.h> +#include <osmocom/core/crc16.h> #include <osmocom/core/logging.h> #include <osmocom/core/linuxlist.h> #include <osmocom/core/rate_ctr.h> #include <osmocom/core/stats.h> #include <osmocom/core/talloc.h> +#include <osmocom/core/utils.h> #include <osmocom/gsm/tlv.h> #include <string.h> @@ -331,6 +333,101 @@ } } return count; + +} +/*********************************************************************** + * IMSI cache + ***********************************************************************/ +static inline uint16_t _checksum_imsi(const char *imsi) +{ + size_t len = strlen(imsi); + return osmo_crc16(0, (const uint8_t *)imsi, len); +} + +static inline struct gbproxy_imsi_cache_entry *_get_imsi_entry(struct gbproxy_config *cfg, const char *imsi) +{ + struct gbproxy_imsi_cache_entry *cache_entry; + uint16_t imsi_hash = _checksum_imsi(imsi); + + hash_for_each_possible(cfg->imsi_cache.entries, cache_entry, list, imsi_hash) { + if (!strncmp(cache_entry->imsi, imsi, sizeof(cache_entry->imsi))) + return cache_entry; + } + return NULL; +} + +void gbproxy_imsi_cache_update(struct gbproxy_nse *nse, const char *imsi) +{ + struct gbproxy_config *cfg = nse->cfg; + struct timespec now; + struct gbproxy_imsi_cache_entry *cache_entry = _get_imsi_entry(cfg, imsi); + uint16_t imsi_hash = _checksum_imsi(imsi); + + osmo_clock_gettime(CLOCK_MONOTONIC, &now); + + if (cache_entry) { + /* Update the entry if it already exists */ + cache_entry->nse = nse; + cache_entry->tstamp = now.tv_sec; + return; + } + + cache_entry = talloc_zero(cfg, struct gbproxy_imsi_cache_entry); + OSMO_STRLCPY_ARRAY(cache_entry->imsi, imsi); + cache_entry->nse = nse; + cache_entry->tstamp = now.tv_sec; + hash_add(cfg->imsi_cache.entries, &cache_entry->list, imsi_hash); +} + +static void _imsi_cache_remove_nse(struct gbproxy_nse *nse) { + uint i; + struct gbproxy_config *cfg = nse->cfg; + struct gbproxy_imsi_cache_entry *imsi_cache; + struct hlist_node *tmp; + + hash_for_each_safe(cfg->imsi_cache.entries, i, tmp, imsi_cache, list) { + if (imsi_cache->nse == nse) { + hash_del(&imsi_cache->list); + talloc_free(imsi_cache); + } + } +} + +void gbproxy_imsi_cache_remove(struct gbproxy_config *cfg, const char *imsi) +{ + struct gbproxy_imsi_cache_entry *imsi_cache; + struct hlist_node *tmp; + uint16_t imsi_hash = _checksum_imsi(imsi); + + hash_for_each_possible_safe(cfg->imsi_cache.entries, imsi_cache, tmp, list, imsi_hash) { + if (!(strncmp(imsi_cache->imsi, imsi, sizeof(imsi_cache->imsi)))) { + hash_del(&imsi_cache->list); + talloc_free(imsi_cache); + return; + } + } +} + +int gbproxy_imsi_cache_cleanup(struct gbproxy_config *cfg) +{ + int i, count = 0; + struct gbproxy_imsi_cache_entry *imsi_cache; + struct hlist_node *tmp; + struct timespec now; + time_t expiry; + + osmo_clock_gettime(CLOCK_MONOTONIC, &now); + expiry = now.tv_sec - cfg->imsi_cache.timeout; + + hash_for_each_safe(cfg->imsi_cache.entries, i, tmp, imsi_cache, list) { + if (imsi_cache->tstamp < expiry) { + count++; + LOGP(DGPRS, LOGL_NOTICE, "Cache entry for IMSI %s expired, removing\n", imsi_cache->imsi); + hash_del(&imsi_cache->list); + talloc_free(imsi_cache); + } + } + return count; } /*********************************************************************** @@ -374,8 +471,9 @@ LOGPNSE_CAT(nse, DOBJ, LOGL_INFO, "NSE Destroying\n"); hash_del(&nse->list); - /* Clear the tlli_cache from this NSE */ + /* Clear the cache entries of this NSE */ _tlli_cache_remove_nse(nse); + _imsi_cache_remove_nse(nse); hash_for_each_safe(nse->bvcs, i, tmp, bvc, list) gbproxy_bvc_free(bvc); @@ -444,6 +542,17 @@ return NULL; } +struct gbproxy_nse *gbproxy_nse_by_imsi(struct gbproxy_config *cfg, const char *imsi) +{ + struct gbproxy_imsi_cache_entry *imsi_cache; + uint16_t imsi_hash = _checksum_imsi(imsi); + + hash_for_each_possible(cfg->imsi_cache.entries, imsi_cache, list, imsi_hash) { + if (!strncmp(imsi_cache->imsi, imsi, sizeof(imsi_cache->imsi))) + return imsi_cache->nse; + } + return NULL; +} /*********************************************************************** * SGSN - Serving GPRS Support Node -- To view, visit https://gerrit.osmocom.org/c/osmo-sgsn/+/22251 To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: osmo-sgsn Gerrit-Branch: master Gerrit-Change-Id: If0a8d6cc1d63f2fb2c395cc5d4373a915bc2cb87 Gerrit-Change-Number: 22251 Gerrit-PatchSet: 2 Gerrit-Owner: daniel <dwillmann at sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: daniel <dwillmann at sysmocom.de> Gerrit-Reviewer: laforge <laforge at osmocom.org> Gerrit-Reviewer: lynxis lazus <lynxis at fe80.eu> Gerrit-MessageType: merged -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20210118/c25d24b8/attachment.htm>