summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJacob Erlbeck <jerlbeck@sysmocom.de>2015-01-19 18:01:42 +0100
committerJacob Erlbeck <jerlbeck@sysmocom.de>2015-01-20 11:37:42 +0100
commit8d7aaa590e9b952eef001ba01150e8e58c7debd2 (patch)
tree352ad510082360cfbbcabde139bd75d4ff25ddf8
parent647ae2ff68b4e9a95c62b5837bf7330eb9a9aa2d (diff)
sgsn: Remove inactive LLME/MM after inactivity timeout (TODO)
Currently old LLMEs and MM contexts that haven't been explicitly detached or cancelled are not removed until another request with the same IMSI is made. These stale entries may accumulate over time and severely compromise the operation of the SGSN. This patch implements age based LLME expiry, when the maximum age has been reached, the corresponding MM context is removed. If such an MM context doesn't exist, the LLME is unassigned directly. TODO: - split commit - replace hard-coded values by real config - Consider: age_timeout -> age, timeout: age = (age == RESET ? 1 : age + TICK) Ticket: OW#1364 Sponsored-by: On-Waves ehf
-rw-r--r--openbsc/include/openbsc/gprs_llc.h5
-rw-r--r--openbsc/include/openbsc/gprs_sgsn.h1
-rw-r--r--openbsc/include/openbsc/sgsn.h2
-rw-r--r--openbsc/src/gprs/Makefile.am2
-rw-r--r--openbsc/src/gprs/gprs_gmm.c10
-rw-r--r--openbsc/src/gprs/gprs_llc.c4
-rw-r--r--openbsc/src/gprs/gprs_llc_vty.c7
-rw-r--r--openbsc/src/gprs/gprs_sgsn.c64
-rw-r--r--openbsc/src/gprs/sgsn_main.c1
-rw-r--r--openbsc/tests/sgsn/Makefile.am2
10 files changed, 94 insertions, 4 deletions
diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h
index fc6216ccc..d54b72e4a 100644
--- a/openbsc/include/openbsc/gprs_llc.h
+++ b/openbsc/include/openbsc/gprs_llc.h
@@ -161,8 +161,13 @@ struct gprs_llc_llme {
uint16_t bvci;
uint16_t nsei;
struct gprs_llc_lle lle[NUM_SAPIS];
+
+ /* Internal management */
+ uint32_t age_timestamp;
};
+#define GPRS_LLME_RESET_AGE (0)
+
extern struct llist_head gprs_llc_llmes;
/* LLC low level types */
diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h
index ad7463e3e..ef9e84474 100644
--- a/openbsc/include/openbsc/gprs_sgsn.h
+++ b/openbsc/include/openbsc/gprs_sgsn.h
@@ -246,6 +246,7 @@ extern struct llist_head sgsn_apn_ctxts;
extern struct llist_head sgsn_pdp_ctxts;
uint32_t sgsn_alloc_ptmsi(void);
+void sgsn_inst_init(void);
/* High-level function to be called in case a GGSN has disappeared or
* ottherwise lost state (recovery procedure) */
diff --git a/openbsc/include/openbsc/sgsn.h b/openbsc/include/openbsc/sgsn.h
index 8a4514627..017bc7fb8 100644
--- a/openbsc/include/openbsc/sgsn.h
+++ b/openbsc/include/openbsc/sgsn.h
@@ -52,6 +52,8 @@ struct sgsn_instance {
struct gsn_t *gsn;
/* Subscriber */
struct gprs_gsup_client *gsup_client;
+ /* LMME inactivity timer */
+ struct osmo_timer_list llme_timer;
};
extern struct sgsn_instance *sgsn;
diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am
index bdbad1921..bc3e21e1b 100644
--- a/openbsc/src/gprs/Makefile.am
+++ b/openbsc/src/gprs/Makefile.am
@@ -27,4 +27,4 @@ osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \
gsm_04_08_gprs.c
osmo_sgsn_LDADD = \
$(top_builddir)/src/libcommon/libcommon.a \
- -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS)
+ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) -lrt
diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c
index 32fb8e49d..5a6aa5b25 100644
--- a/openbsc/src/gprs/gprs_gmm.c
+++ b/openbsc/src/gprs/gprs_gmm.c
@@ -50,6 +50,7 @@
#include <openbsc/gprs_llc.h>
#include <openbsc/gprs_sgsn.h>
#include <openbsc/gprs_gmm.h>
+#include <openbsc/gprs_utils.h>
#include <openbsc/sgsn.h>
#include <pdp.h>
@@ -338,8 +339,12 @@ static int gsm48_tx_gmm_att_ack(struct sgsn_mm_ctx *mm)
ptsig[1] = mm->p_tmsi_sig >> 8;
ptsig[2] = mm->p_tmsi_sig & 0xff;
- /* Optional: Negotiated Ready timer value */
#endif
+ /* Optional: Negotiated Ready timer value
+ * (fixed 44s, default value, GSM 04.08, table 11.4a) to safely limit
+ * the inactivity time READY->STANDBY.
+ */
+ msgb_tv_put(msg, GSM48_IE_GMM_TIMER_READY, gprs_secs_to_tmr_floor(44));
#ifdef PTMSI_ALLOC
/* Optional: Allocated P-TMSI */
@@ -992,6 +997,9 @@ static int gsm48_tx_gmm_ra_upd_ack(struct sgsn_mm_ctx *mm)
mid[0] = GSM48_IE_GMM_ALLOC_PTMSI;
#endif
+ /* Optional: Negotiated READY timer value */
+ msgb_tv_put(msg, GSM48_IE_GMM_TIMER_READY, gprs_secs_to_tmr_floor(44));
+
/* Option: MS ID, ... */
return gsm48_gmm_sendmsg(msg, 0, mm);
}
diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c
index c2c65d951..5cd7ead15 100644
--- a/openbsc/src/gprs/gprs_llc.c
+++ b/openbsc/src/gprs/gprs_llc.c
@@ -267,6 +267,7 @@ static struct gprs_llc_llme *llme_alloc(uint32_t tlli)
llme->tlli = tlli;
llme->old_tlli = 0xffffffff;
llme->state = GPRS_LLMS_UNASSIGNED;
+ llme->age_timestamp = GPRS_LLME_RESET_AGE;
for (i = 0; i < ARRAY_SIZE(llme->lle); i++)
lle_init(llme, i);
@@ -633,6 +634,9 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv)
return 0;
}
+ /* reset age computation */
+ lle->llme->age_timestamp = GPRS_LLME_RESET_AGE;
+
/* decrypt information field + FCS, if needed! */
if (llhp.is_encrypted) {
uint32_t iov_ui = 0; /* FIXME: randomly select for TLLI */
diff --git a/openbsc/src/gprs/gprs_llc_vty.c b/openbsc/src/gprs/gprs_llc_vty.c
index ab5269922..f399b2752 100644
--- a/openbsc/src/gprs/gprs_llc_vty.c
+++ b/openbsc/src/gprs/gprs_llc_vty.c
@@ -23,6 +23,7 @@
#include <unistd.h>
#include <errno.h>
#include <stdint.h>
+#include <time.h>
#include <arpa/inet.h>
@@ -69,9 +70,13 @@ static uint8_t valid_sapis[] = { 1, 2, 3, 5, 7, 8, 9, 11 };
static void vty_dump_llme(struct vty *vty, struct gprs_llc_llme *llme)
{
unsigned int i;
+ struct timespec now_tp = {0};
+ clock_gettime(CLOCK_MONOTONIC, &now_tp);
- vty_out(vty, "TLLI %08x (Old TLLI %08x) BVCI=%u NSEI=%u: State %s%s",
+ vty_out(vty, "TLLI %08x (Old TLLI %08x) BVCI=%u NSEI=%u Age=%d: State %s%s",
llme->tlli, llme->old_tlli, llme->bvci, llme->nsei,
+ llme->age_timestamp == GPRS_LLME_RESET_AGE ? 0 :
+ (int)(now_tp.tv_sec - (time_t)llme->age_timestamp),
get_value_string(gprs_llc_state_strs, llme->state), VTY_NEWLINE);
for (i = 0; i < ARRAY_SIZE(valid_sapis); i++) {
diff --git a/openbsc/src/gprs/gprs_sgsn.c b/openbsc/src/gprs/gprs_sgsn.c
index 6f706642d..1427b1afb 100644
--- a/openbsc/src/gprs/gprs_sgsn.c
+++ b/openbsc/src/gprs/gprs_sgsn.c
@@ -37,6 +37,10 @@
#include <openbsc/gprs_gmm.h>
#include "openbsc/gprs_llc.h"
+#include <time.h>
+
+#define GPRS_LLME_CHECK_TICK 30
+
extern struct sgsn_instance *sgsn;
LLIST_HEAD(sgsn_mm_ctxts);
@@ -508,3 +512,63 @@ void sgsn_update_subscriber_data(struct sgsn_mm_ctx *mmctx,
sgsn_auth_update(mmctx);
}
+
+static void sgsn_llme_cleanup_free(struct gprs_llc_llme *llme)
+{
+ struct sgsn_mm_ctx *mmctx = NULL;
+
+ llist_for_each_entry(mmctx, &sgsn_mm_ctxts, list) {
+ if (llme == mmctx->llme) {
+ gsm0408_gprs_access_cancelled(mmctx, SGSN_ERROR_CAUSE_NONE);
+ return;
+ }
+ }
+
+ /* No MM context found */
+ LOGP(DGPRS, LOGL_INFO, "Deleting orphaned LLME, TLLI 0x%08x\n",
+ llme->tlli);
+ gprs_llgmm_assign(llme, llme->tlli, 0xffffffff, GPRS_ALGO_GEA0, NULL);
+}
+
+static void sgsn_llme_check_cb(void *data_)
+{
+ struct gprs_llc_llme *llme, *llme_tmp;
+ struct timespec now_tp;
+ time_t now, age;
+
+ int rc;
+
+ rc = clock_gettime(CLOCK_MONOTONIC, &now_tp);
+ OSMO_ASSERT(rc >= 0);
+ now = now_tp.tv_sec;
+
+ LOGP(DGPRS, LOGL_DEBUG,
+ "Checking for inactive LLMEs, time = %u\n", (unsigned)now);
+
+ llist_for_each_entry_safe(llme, llme_tmp, &gprs_llc_llmes, list) {
+ if (llme->age_timestamp == GPRS_LLME_RESET_AGE)
+ llme->age_timestamp = now;
+
+ age = now - llme->age_timestamp;
+
+ /* TODO: derive time from setting / mmctx.
+ * Currently hard-coded to 10min + 4min + 44s */
+ if (age > 16 * 60 || age < 0) {
+ LOGP(DGPRS, LOGL_INFO,
+ "Inactivity timeout for TLLI 0x%08x, age %d\n",
+ llme->tlli, (int)age);
+ sgsn_llme_cleanup_free(llme);
+ }
+ }
+
+ osmo_timer_schedule(&sgsn->llme_timer, GPRS_LLME_CHECK_TICK, 0);
+}
+
+void sgsn_inst_init()
+{
+ sgsn->llme_timer.cb = sgsn_llme_check_cb;
+ sgsn->llme_timer.data = NULL;
+
+ osmo_timer_schedule(&sgsn->llme_timer, GPRS_LLME_CHECK_TICK, 0);
+}
+
diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c
index f26b812a8..0db90d5c3 100644
--- a/openbsc/src/gprs/sgsn_main.c
+++ b/openbsc/src/gprs/sgsn_main.c
@@ -337,6 +337,7 @@ int main(int argc, char **argv)
bssgp_nsi = sgsn_inst.cfg.nsi = sgsn_nsi;
gprs_llc_init("/usr/local/lib/osmocom/crypt/");
+ sgsn_inst_init();
gprs_ns_vty_init(bssgp_nsi);
bssgp_vty_init();
diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am
index c1b5fbda4..693cf792a 100644
--- a/openbsc/tests/sgsn/Makefile.am
+++ b/openbsc/tests/sgsn/Makefile.am
@@ -32,5 +32,5 @@ sgsn_test_LDADD = \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOGSM_LIBS) \
$(LIBOSMOGB_LIBS) \
- -lgtp
+ -lgtp -lrt