<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>