<p>daniel <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/osmo-sgsn/+/21960">View Change</a></p><div style="white-space:pre-wrap">Approvals:
daniel: Looks good to me, approved
Jenkins Builder: Verified
</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">gbproxy: Implement TLLI cache and use it for SUSPEND/RESUME<br><br>When routing a SUSPEND/RESUME we need to keep track of where it came<br>from so we can send the (N)ACK back to the correct BSS. Use the TLLI<br>which is present in both messages to cache and retrieve the correct BSS.<br><br>A timer runs every two seconds and expires entries that are older than<br>the timeout (hardcoded to 5 seconds for now).<br><br>Related: SYS#4865, OS#4472<br>Change-Id: I42adf70f560d2bb358a9e1c7614281e8d2967568<br>---<br>M include/osmocom/sgsn/gb_proxy.h<br>M src/gbproxy/gb_proxy.c<br>M src/gbproxy/gb_proxy_peer.c<br>3 files changed, 175 insertions(+), 10 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmocom/sgsn/gb_proxy.h b/include/osmocom/sgsn/gb_proxy.h</span><br><span>index ad5bb27..04a3c4b 100644</span><br><span>--- a/include/osmocom/sgsn/gb_proxy.h</span><br><span>+++ b/include/osmocom/sgsn/gb_proxy.h</span><br><span>@@ -75,6 +75,14 @@</span><br><span> /* hash table of all gbproxy_cell */</span><br><span> DECLARE_HASHTABLE(cells, 8);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* tlli<->nse cache used to map SUSPEND/RESUME (N)ACKS */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct {</span><br><span style="color: hsl(120, 100%, 40%);">+ DECLARE_HASHTABLE(entries, 10);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_timer_list timer;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Time in seconds that the entries should be valid */</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t timeout;</span><br><span style="color: hsl(120, 100%, 40%);">+ } tlli_cache;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* List of all SGSNs */</span><br><span> struct llist_head sgsns;</span><br><span> </span><br><span>@@ -163,6 +171,19 @@</span><br><span> } pool;</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* TLLI cache */</span><br><span style="color: hsl(120, 100%, 40%);">+struct gbproxy_tlli_cache_entry {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* linked to gbproxy_config.tlli_cache */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct hlist_node list;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* TLLI of the entry */</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t tlli;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* When was this entry last seen */</span><br><span style="color: hsl(120, 100%, 40%);">+ time_t tstamp;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* The Cell this TLLI was last seen */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_nse *nse;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Convenience logging macros for NSE/BVC */</span><br><span> #define LOGPNSE_CAT(NSE, SUBSYS, LEVEL, FMT, ARGS...) \</span><br><span> LOGP(SUBSYS, LEVEL, "NSE(%05u/%s) " FMT, (NSE)->nsei, \</span><br><span>@@ -229,6 +250,12 @@</span><br><span> void gbproxy_nse_free(struct gbproxy_nse *nse);</span><br><span> struct gbproxy_nse *gbproxy_nse_by_nsei(struct gbproxy_config *cfg, uint16_t nsei, uint32_t flags);</span><br><span> struct gbproxy_nse *gbproxy_nse_by_nsei_or_new(struct gbproxy_config *cfg, uint16_t nsei, bool sgsn_facing);</span><br><span style="color: hsl(120, 100%, 40%);">+struct gbproxy_nse *gbproxy_nse_by_tlli(struct gbproxy_config *cfg, uint32_t tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* TLLI cache */</span><br><span style="color: hsl(120, 100%, 40%);">+void gbproxy_tlli_cache_update(struct gbproxy_nse *nse, uint32_t tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+void gbproxy_tlli_cache_remove(struct gbproxy_config *cfg, uint32_t tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+int gbproxy_tlli_cache_cleanup(struct gbproxy_config *cfg);</span><br><span> </span><br><span> /* SGSN handling */</span><br><span> struct gbproxy_sgsn *gbproxy_sgsn_alloc(struct gbproxy_config *cfg, uint16_t nsei, const char *name);</span><br><span>diff --git a/src/gbproxy/gb_proxy.c b/src/gbproxy/gb_proxy.c</span><br><span>index 34cff31..91324dd 100644</span><br><span>--- a/src/gbproxy/gb_proxy.c</span><br><span>+++ b/src/gbproxy/gb_proxy.c</span><br><span>@@ -890,11 +890,20 @@</span><br><span> return osmo_fsm_inst_dispatch(from_bvc->fi, BSSGP_BVCFSM_E_RX_UNBLOCK, msg);</span><br><span> case BSSGP_PDUT_SUSPEND:</span><br><span> case BSSGP_PDUT_RESUME:</span><br><span style="color: hsl(0, 100%, 40%);">- /* FIXME: Implement TLLI Cache. Every SUSPEND/RESUME we must</span><br><span style="color: hsl(0, 100%, 40%);">- * take record of the TLLI->BVC mapping so we can map</span><br><span style="color: hsl(0, 100%, 40%);">- * back from TLLI->BVC when the SUSPEND/RESUME-ACK</span><br><span style="color: hsl(0, 100%, 40%);">- * arrives. Cache should have a timeout of 1-3 seconds</span><br><span style="color: hsl(0, 100%, 40%);">- * and the ACK should explicitly delete entries. */</span><br><span style="color: hsl(120, 100%, 40%);">+ {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_sgsn *sgsn;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ tlli = osmo_load32be(TLVP_VAL(&tp, BSSGP_IE_TLLI));</span><br><span style="color: hsl(120, 100%, 40%);">+ sgsn = gbproxy_select_sgsn(nse->cfg, &tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!sgsn) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DGPRS, LOGL_ERROR, "Could not find any SGSN for TLLI, dropping message!\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ gbproxy_tlli_cache_update(nse, tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = gbprox_relay2nse(msg, sgsn->nse, 0);</span><br><span> #if 0</span><br><span> /* TODO: Validate the RAI for consistency with the RAI</span><br><span> * we expect for any of the BVC within this BSS side NSE */</span><br><span>@@ -902,6 +911,7 @@</span><br><span> gsm48_parse_ra(&raid, from_bvc->ra);</span><br><span> #endif</span><br><span> break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> case BSSGP_PDUT_STATUS:</span><br><span> /* FIXME: inspect the erroneous PDU IE (if any) and check</span><br><span> * if we can extract a TLLI/RNI to route it to the correct SGSN */</span><br><span>@@ -1149,11 +1159,22 @@</span><br><span> case BSSGP_PDUT_SUSPEND_NACK:</span><br><span> case BSSGP_PDUT_RESUME_ACK:</span><br><span> case BSSGP_PDUT_RESUME_NACK:</span><br><span style="color: hsl(0, 100%, 40%);">- /* FIXME: handle based on TLLI cache. The RA-ID is not a unique</span><br><span style="color: hsl(0, 100%, 40%);">- * criterion, so we have to rely on the TLLI->BVC state created</span><br><span style="color: hsl(0, 100%, 40%);">- * while processing the SUSPEND/RESUME in uplink */</span><br><span style="color: hsl(0, 100%, 40%);">- /* FIXME: route to SGSN baed on NRI derived from TLLI */</span><br><span style="color: hsl(120, 100%, 40%);">+ {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_nse *nse_peer;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t tlli = osmo_load32be(TLVP_VAL(&tp, BSSGP_IE_TLLI));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ nse_peer = gbproxy_nse_by_tlli(cfg, tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!nse_peer) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPNSE(nse, LOGL_ERROR, "Rx %s: Cannot find NSE\n", pdut_name);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* TODO: Counter */</span><br><span style="color: hsl(120, 100%, 40%);">+ return bssgp_tx_status(BSSGP_CAUSE_INV_MAND_INF, NULL, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Delete the entry after we're done */</span><br><span style="color: hsl(120, 100%, 40%);">+ gbproxy_tlli_cache_remove(cfg, tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPNSE(nse_peer, LOGL_DEBUG, "Rx %s: forwarding\n", pdut_name);</span><br><span style="color: hsl(120, 100%, 40%);">+ gbprox_relay2nse(msg, nse_peer, ns_bvci);</span><br><span> break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> case BSSGP_PDUT_SGSN_INVOKE_TRACE:</span><br><span> case BSSGP_PDUT_OVERLOAD:</span><br><span> LOGPNSE(nse, LOGL_DEBUG, "Rx %s: broadcasting\n", pdut_name);</span><br><span>@@ -1375,6 +1396,15 @@</span><br><span> gbproxy_init_config(cfg);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static void tlli_cache_cleanup(void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_config *cfg = data;</span><br><span style="color: hsl(120, 100%, 40%);">+ gbproxy_tlli_cache_cleanup(cfg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* TODO: Disable timer when cache is empty */</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_timer_schedule(&cfg->tlli_cache.timer, 2, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> int gbproxy_init_config(struct gbproxy_config *cfg)</span><br><span> {</span><br><span> struct timespec tp;</span><br><span>@@ -1382,12 +1412,18 @@</span><br><span> /* by default we advertise 100% of the BSS-side capacity to _each_ SGSN */</span><br><span> cfg->pool.bvc_fc_ratio = 100;</span><br><span> cfg->pool.null_nri_ranges = osmo_nri_ranges_alloc(cfg);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* TODO: Make configurable */</span><br><span style="color: hsl(120, 100%, 40%);">+ cfg->tlli_cache.timeout = 5;</span><br><span> </span><br><span> hash_init(cfg->bss_nses);</span><br><span> hash_init(cfg->sgsn_nses);</span><br><span> hash_init(cfg->cells);</span><br><span style="color: hsl(120, 100%, 40%);">+ hash_init(cfg->tlli_cache.entries);</span><br><span> INIT_LLIST_HEAD(&cfg->sgsns);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_timer_setup(&cfg->tlli_cache.timer, tlli_cache_cleanup, cfg);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_timer_schedule(&cfg->tlli_cache.timer, 2, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> cfg->ctrg = rate_ctr_group_alloc(tall_sgsn_ctx, &global_ctrg_desc, 0);</span><br><span> if (!cfg->ctrg) {</span><br><span> LOGP(DGPRS, LOGL_ERROR, "Cannot allocate global counter group!\n");</span><br><span>@@ -1397,4 +1433,4 @@</span><br><span> osmo_fsm_log_timeouts(true);</span><br><span> </span><br><span> return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>\ No newline at end of file</span><br><span>diff --git a/src/gbproxy/gb_proxy_peer.c b/src/gbproxy/gb_proxy_peer.c</span><br><span>index d2ddfc1..104902b 100644</span><br><span>--- a/src/gbproxy/gb_proxy_peer.c</span><br><span>+++ b/src/gbproxy/gb_proxy_peer.c</span><br><span>@@ -192,6 +192,17 @@</span><br><span> return NULL;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static inline struct gbproxy_tlli_cache_entry *_get_tlli_entry(struct gbproxy_config *cfg, uint32_t tlli)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_tlli_cache_entry *cache_entry;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ hash_for_each_possible(cfg->tlli_cache.entries, cache_entry, list, tlli) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (cache_entry->tlli == tlli)</span><br><span style="color: hsl(120, 100%, 40%);">+ return cache_entry;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct gbproxy_cell *gbproxy_cell_by_bvci_or_new(struct gbproxy_config *cfg, uint16_t bvci)</span><br><span> {</span><br><span> struct gbproxy_cell *cell;</span><br><span>@@ -245,6 +256,83 @@</span><br><span> return false;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/***********************************************************************</span><br><span style="color: hsl(120, 100%, 40%);">+ * TLLI cache</span><br><span style="color: hsl(120, 100%, 40%);">+ ***********************************************************************/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void gbproxy_tlli_cache_update(struct gbproxy_nse *nse, uint32_t tlli)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_config *cfg = nse->cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct timespec now;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_tlli_cache_entry *cache_entry = _get_tlli_entry(cfg, tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_clock_gettime(CLOCK_MONOTONIC, &now);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (cache_entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Update the entry if it already exists */</span><br><span style="color: hsl(120, 100%, 40%);">+ cache_entry->nse = nse;</span><br><span style="color: hsl(120, 100%, 40%);">+ cache_entry->tstamp = now.tv_sec;</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ cache_entry = talloc_zero(cfg, struct gbproxy_tlli_cache_entry);</span><br><span style="color: hsl(120, 100%, 40%);">+ cache_entry->tlli = tlli;</span><br><span style="color: hsl(120, 100%, 40%);">+ cache_entry->nse = nse;</span><br><span style="color: hsl(120, 100%, 40%);">+ cache_entry->tstamp = now.tv_sec;</span><br><span style="color: hsl(120, 100%, 40%);">+ hash_add(cfg->tlli_cache.entries, &cache_entry->list, cache_entry->tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void _tlli_cache_remove_nse(struct gbproxy_nse *nse) {</span><br><span style="color: hsl(120, 100%, 40%);">+ uint i;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_config *cfg = nse->cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_tlli_cache_entry *tlli_cache;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct hlist_node *tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ hash_for_each_safe(cfg->tlli_cache.entries, i, tmp, tlli_cache, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (tlli_cache->nse == nse) {</span><br><span style="color: hsl(120, 100%, 40%);">+ hash_del(&tlli_cache->list);</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(tlli_cache);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void gbproxy_tlli_cache_remove(struct gbproxy_config *cfg, uint32_t tlli)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_tlli_cache_entry *tlli_cache;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct hlist_node *tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ hash_for_each_possible_safe(cfg->tlli_cache.entries, tlli_cache, tmp, list, tlli) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (tlli_cache->tlli == tlli) {</span><br><span style="color: hsl(120, 100%, 40%);">+ hash_del(&tlli_cache->list);</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(tlli_cache);</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int gbproxy_tlli_cache_cleanup(struct gbproxy_config *cfg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int i, count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_tlli_cache_entry *tlli_cache;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct hlist_node *tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct timespec now;</span><br><span style="color: hsl(120, 100%, 40%);">+ time_t expiry;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_clock_gettime(CLOCK_MONOTONIC, &now);</span><br><span style="color: hsl(120, 100%, 40%);">+ expiry = now.tv_sec - cfg->tlli_cache.timeout;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ hash_for_each_safe(cfg->tlli_cache.entries, i, tmp, tlli_cache, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (tlli_cache->tstamp < expiry) {</span><br><span style="color: hsl(120, 100%, 40%);">+ count++;</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DGPRS, LOGL_NOTICE, "Cache entry for TLLI %08x expired, removing\n", tlli_cache->tlli);</span><br><span style="color: hsl(120, 100%, 40%);">+ hash_del(&tlli_cache->list);</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(tlli_cache);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ return count;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /***********************************************************************</span><br><span> * NSE - NS Entity</span><br><span> ***********************************************************************/</span><br><span>@@ -286,6 +374,8 @@</span><br><span> LOGPNSE_CAT(nse, DOBJ, LOGL_INFO, "NSE Destroying\n");</span><br><span> </span><br><span> hash_del(&nse->list);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Clear the tlli_cache from this NSE */</span><br><span style="color: hsl(120, 100%, 40%);">+ _tlli_cache_remove_nse(nse);</span><br><span> </span><br><span> hash_for_each_safe(nse->bvcs, i, tmp, bvc, list)</span><br><span> gbproxy_bvc_free(bvc);</span><br><span>@@ -343,6 +433,18 @@</span><br><span> return nse;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct gbproxy_nse *gbproxy_nse_by_tlli(struct gbproxy_config *cfg, uint32_t tlli)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_tlli_cache_entry *tlli_cache;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ hash_for_each_possible(cfg->tlli_cache.entries, tlli_cache, list, tlli) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (tlli_cache->tlli == tlli)</span><br><span style="color: hsl(120, 100%, 40%);">+ return tlli_cache->nse;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /***********************************************************************</span><br><span> * SGSN - Serving GPRS Support Node</span><br><span> ***********************************************************************/</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-sgsn/+/21960">change 21960</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-sgsn/+/21960"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: osmo-sgsn </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I42adf70f560d2bb358a9e1c7614281e8d2967568 </div>
<div style="display:none"> Gerrit-Change-Number: 21960 </div>
<div style="display:none"> Gerrit-PatchSet: 5 </div>
<div style="display:none"> Gerrit-Owner: daniel <dwillmann@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: daniel <dwillmann@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>