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
diff --git a/src/gb_proxy.c b/src/gb_proxy.c
index 7f8260c..d8bca58 100644
--- a/src/gb_proxy.c
+++ b/src/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");