Change in osmo-sgsn[master]: gbproxy: Implement TLLI cache and use it for SUSPEND/RESUME

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.org
Mon Jan 11 14:19:14 UTC 2021


daniel has submitted this change. ( https://gerrit.osmocom.org/c/osmo-sgsn/+/21960 )

Change subject: gbproxy: Implement TLLI cache and use it for SUSPEND/RESUME
......................................................................

gbproxy: Implement TLLI cache and use it for SUSPEND/RESUME

When routing a SUSPEND/RESUME we need to keep track of where it came
from so we can send the (N)ACK back to the correct BSS. Use the TLLI
which is present in both messages to cache and retrieve the correct BSS.

A timer runs every two seconds and expires entries that are older than
the timeout (hardcoded to 5 seconds for now).

Related: SYS#4865, OS#4472
Change-Id: I42adf70f560d2bb358a9e1c7614281e8d2967568
---
M include/osmocom/sgsn/gb_proxy.h
M src/gbproxy/gb_proxy.c
M src/gbproxy/gb_proxy_peer.c
3 files changed, 175 insertions(+), 10 deletions(-)

Approvals:
  daniel: Looks good to me, approved
  Jenkins Builder: Verified



diff --git a/include/osmocom/sgsn/gb_proxy.h b/include/osmocom/sgsn/gb_proxy.h
index ad5bb27..04a3c4b 100644
--- a/include/osmocom/sgsn/gb_proxy.h
+++ b/include/osmocom/sgsn/gb_proxy.h
@@ -75,6 +75,14 @@
 	/* hash table of all gbproxy_cell */
 	DECLARE_HASHTABLE(cells, 8);
 
+	/* tlli<->nse cache used to map SUSPEND/RESUME (N)ACKS */
+	struct {
+		DECLARE_HASHTABLE(entries, 10);
+		struct osmo_timer_list timer;
+		/* Time in seconds that the entries should be valid */
+		uint8_t timeout;
+	} tlli_cache;
+
 	/* List of all SGSNs */
 	struct llist_head sgsns;
 
@@ -163,6 +171,19 @@
 	} pool;
 };
 
+/* TLLI cache */
+struct gbproxy_tlli_cache_entry {
+	/* linked to gbproxy_config.tlli_cache */
+	struct hlist_node list;
+
+	/* TLLI of the entry */
+	uint32_t tlli;
+	/* When was this entry last seen */
+	time_t tstamp;
+	/* The Cell this TLLI was last seen */
+	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, \
@@ -229,6 +250,12 @@
 void gbproxy_nse_free(struct gbproxy_nse *nse);
 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);
+
+/* 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);
 
 /* SGSN handling */
 struct gbproxy_sgsn *gbproxy_sgsn_alloc(struct gbproxy_config *cfg, uint16_t nsei, const char *name);
diff --git a/src/gbproxy/gb_proxy.c b/src/gbproxy/gb_proxy.c
index 34cff31..91324dd 100644
--- a/src/gbproxy/gb_proxy.c
+++ b/src/gbproxy/gb_proxy.c
@@ -890,11 +890,20 @@
 		return osmo_fsm_inst_dispatch(from_bvc->fi, BSSGP_BVCFSM_E_RX_UNBLOCK, msg);
 	case BSSGP_PDUT_SUSPEND:
 	case BSSGP_PDUT_RESUME:
-		/* FIXME: Implement TLLI Cache.  Every SUSPEND/RESUME we must
-		 * take record of the TLLI->BVC mapping so we can map
-		 * back from TLLI->BVC when the SUSPEND/RESUME-ACK
-		 * arrives.  Cache should have a timeout of 1-3 seconds
-		 * and the ACK should explicitly delete entries. */
+	{
+		struct gbproxy_sgsn *sgsn;
+
+		tlli = osmo_load32be(TLVP_VAL(&tp, BSSGP_IE_TLLI));
+		sgsn = gbproxy_select_sgsn(nse->cfg, &tlli);
+		if (!sgsn) {
+			LOGP(DGPRS, LOGL_ERROR, "Could not find any SGSN for TLLI, dropping message!\n");
+			rc = -EINVAL;
+			break;
+		}
+
+		gbproxy_tlli_cache_update(nse, tlli);
+
+		rc = gbprox_relay2nse(msg, sgsn->nse, 0);
 #if 0
 		/* TODO: Validate the RAI for consistency with the RAI
 		 * we expect for any of the BVC within this BSS side NSE */
@@ -902,6 +911,7 @@
 		gsm48_parse_ra(&raid, from_bvc->ra);
 #endif
 		break;
+	}
 	case BSSGP_PDUT_STATUS:
 		/* FIXME: inspect the erroneous PDU IE (if any) and check
 		 * if we can extract a TLLI/RNI to route it to the correct SGSN */
@@ -1149,11 +1159,22 @@
 	case BSSGP_PDUT_SUSPEND_NACK:
 	case BSSGP_PDUT_RESUME_ACK:
 	case BSSGP_PDUT_RESUME_NACK:
-		/* FIXME: handle based on TLLI cache. The RA-ID is not a unique
-		 * criterion, so we have to rely on the TLLI->BVC state created
-		 * while processing the SUSPEND/RESUME in uplink */
-		/* FIXME: route to SGSN baed on NRI derived from TLLI */
+	{
+		struct gbproxy_nse *nse_peer;
+		uint32_t tlli = osmo_load32be(TLVP_VAL(&tp, BSSGP_IE_TLLI));
+
+		nse_peer = gbproxy_nse_by_tlli(cfg, tlli);
+		if (!nse_peer) {
+			LOGPNSE(nse, LOGL_ERROR, "Rx %s: Cannot find NSE\n", pdut_name);
+			/* TODO: Counter */
+			return bssgp_tx_status(BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
+		}
+		/* Delete the entry after we're done */
+		gbproxy_tlli_cache_remove(cfg, tlli);
+		LOGPNSE(nse_peer, LOGL_DEBUG, "Rx %s: forwarding\n", pdut_name);
+		gbprox_relay2nse(msg, nse_peer, ns_bvci);
 		break;
+	}
 	case BSSGP_PDUT_SGSN_INVOKE_TRACE:
 	case BSSGP_PDUT_OVERLOAD:
 		LOGPNSE(nse, LOGL_DEBUG, "Rx %s: broadcasting\n", pdut_name);
@@ -1375,6 +1396,15 @@
 	gbproxy_init_config(cfg);
 }
 
+static void tlli_cache_cleanup(void *data)
+{
+	struct gbproxy_config *cfg = data;
+	gbproxy_tlli_cache_cleanup(cfg);
+
+	/* TODO: Disable timer when cache is empty */
+	osmo_timer_schedule(&cfg->tlli_cache.timer, 2, 0);
+}
+
 int gbproxy_init_config(struct gbproxy_config *cfg)
 {
 	struct timespec tp;
@@ -1382,12 +1412,18 @@
 	/* by default we advertise 100% of the BSS-side capacity to _each_ SGSN */
 	cfg->pool.bvc_fc_ratio = 100;
 	cfg->pool.null_nri_ranges = osmo_nri_ranges_alloc(cfg);
+	/* TODO: Make configurable */
+	cfg->tlli_cache.timeout = 5;
 
 	hash_init(cfg->bss_nses);
 	hash_init(cfg->sgsn_nses);
 	hash_init(cfg->cells);
+	hash_init(cfg->tlli_cache.entries);
 	INIT_LLIST_HEAD(&cfg->sgsns);
 
+	osmo_timer_setup(&cfg->tlli_cache.timer, tlli_cache_cleanup, cfg);
+	osmo_timer_schedule(&cfg->tlli_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");
@@ -1397,4 +1433,4 @@
 	osmo_fsm_log_timeouts(true);
 
 	return 0;
-}
+}
\ No newline at end of file
diff --git a/src/gbproxy/gb_proxy_peer.c b/src/gbproxy/gb_proxy_peer.c
index d2ddfc1..104902b 100644
--- a/src/gbproxy/gb_proxy_peer.c
+++ b/src/gbproxy/gb_proxy_peer.c
@@ -192,6 +192,17 @@
 	return NULL;
 }
 
+static inline struct gbproxy_tlli_cache_entry *_get_tlli_entry(struct gbproxy_config *cfg, uint32_t tlli)
+{
+	struct gbproxy_tlli_cache_entry *cache_entry;
+
+	hash_for_each_possible(cfg->tlli_cache.entries, cache_entry, list, tlli) {
+		if (cache_entry->tlli == tlli)
+			return cache_entry;
+	}
+	return NULL;
+}
+
 struct gbproxy_cell *gbproxy_cell_by_bvci_or_new(struct gbproxy_config *cfg, uint16_t bvci)
 {
 	struct gbproxy_cell *cell;
@@ -245,6 +256,83 @@
 	return false;
 }
 
+
+/***********************************************************************
+ * TLLI cache
+ ***********************************************************************/
+
+void gbproxy_tlli_cache_update(struct gbproxy_nse *nse, uint32_t tlli)
+{
+	struct gbproxy_config *cfg = nse->cfg;
+	struct timespec now;
+	struct gbproxy_tlli_cache_entry *cache_entry = _get_tlli_entry(cfg, tlli);
+
+	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_tlli_cache_entry);
+	cache_entry->tlli = tlli;
+	cache_entry->nse = nse;
+	cache_entry->tstamp = now.tv_sec;
+	hash_add(cfg->tlli_cache.entries, &cache_entry->list, cache_entry->tlli);
+}
+
+static void _tlli_cache_remove_nse(struct gbproxy_nse *nse) {
+	uint i;
+	struct gbproxy_config *cfg = nse->cfg;
+	struct gbproxy_tlli_cache_entry *tlli_cache;
+	struct hlist_node *tmp;
+
+	hash_for_each_safe(cfg->tlli_cache.entries, i, tmp, tlli_cache, list) {
+		if (tlli_cache->nse == nse) {
+			hash_del(&tlli_cache->list);
+			talloc_free(tlli_cache);
+		}
+	}
+}
+
+void gbproxy_tlli_cache_remove(struct gbproxy_config *cfg, uint32_t tlli)
+{
+	struct gbproxy_tlli_cache_entry *tlli_cache;
+	struct hlist_node *tmp;
+
+	hash_for_each_possible_safe(cfg->tlli_cache.entries, tlli_cache, tmp, list, tlli) {
+		if (tlli_cache->tlli == tlli) {
+			hash_del(&tlli_cache->list);
+			talloc_free(tlli_cache);
+			return;
+		}
+	}
+}
+
+int gbproxy_tlli_cache_cleanup(struct gbproxy_config *cfg)
+{
+	int i, count = 0;
+	struct gbproxy_tlli_cache_entry *tlli_cache;
+	struct hlist_node *tmp;
+	struct timespec now;
+	time_t expiry;
+
+	osmo_clock_gettime(CLOCK_MONOTONIC, &now);
+	expiry = now.tv_sec - cfg->tlli_cache.timeout;
+
+	hash_for_each_safe(cfg->tlli_cache.entries, i, tmp, tlli_cache, list) {
+		if (tlli_cache->tstamp < expiry) {
+			count++;
+			LOGP(DGPRS, LOGL_NOTICE, "Cache entry for TLLI %08x expired, removing\n", tlli_cache->tlli);
+			hash_del(&tlli_cache->list);
+			talloc_free(tlli_cache);
+		}
+	}
+	return count;
+}
+
 /***********************************************************************
  * NSE - NS Entity
  ***********************************************************************/
@@ -286,6 +374,8 @@
 	LOGPNSE_CAT(nse, DOBJ, LOGL_INFO, "NSE Destroying\n");
 
 	hash_del(&nse->list);
+	/* Clear the tlli_cache from this NSE */
+	_tlli_cache_remove_nse(nse);
 
 	hash_for_each_safe(nse->bvcs, i, tmp, bvc, list)
 		gbproxy_bvc_free(bvc);
@@ -343,6 +433,18 @@
 	return nse;
 }
 
+struct gbproxy_nse *gbproxy_nse_by_tlli(struct gbproxy_config *cfg, uint32_t tlli)
+{
+	struct gbproxy_tlli_cache_entry *tlli_cache;
+
+	hash_for_each_possible(cfg->tlli_cache.entries, tlli_cache, list, tlli) {
+		if (tlli_cache->tlli == tlli)
+			return tlli_cache->nse;
+	}
+	return NULL;
+}
+
+
 /***********************************************************************
  * SGSN - Serving GPRS Support Node
  ***********************************************************************/

-- 
To view, visit https://gerrit.osmocom.org/c/osmo-sgsn/+/21960
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-sgsn
Gerrit-Branch: master
Gerrit-Change-Id: I42adf70f560d2bb358a9e1c7614281e8d2967568
Gerrit-Change-Number: 21960
Gerrit-PatchSet: 5
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: pespin <pespin at sysmocom.de>
Gerrit-MessageType: merged
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20210111/d9730f76/attachment.htm>


More information about the gerrit-log mailing list