lynxis lazus submitted this change.

View Change

Approvals: pespin: Looks good to me, but someone else must approve Jenkins Builder: Verified lynxis lazus: Looks good to me, approved daniel: Looks good to me, but someone else must approve
routing area: introduce ran_type on the RA

A Routing Area should be uniquely identified by the RAI.
Following this, it is forbidden to have a RAI which is valid
in both, GERAN and UTRAN.

Change-Id: I59c35f1a4912ff11574bb31e4fe424816993548c
---
M include/osmocom/sgsn/gprs_routing_area.h
M src/sgsn/gprs_routing_area.c
M tests/gprs_routing_area/gprs_routing_area_test.c
3 files changed, 90 insertions(+), 36 deletions(-)

diff --git a/include/osmocom/sgsn/gprs_routing_area.h b/include/osmocom/sgsn/gprs_routing_area.h
index caaed47..020ee17 100644
--- a/include/osmocom/sgsn/gprs_routing_area.h
+++ b/include/osmocom/sgsn/gprs_routing_area.h
@@ -6,6 +6,7 @@
#include <stdint.h>

#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/utils.h>
#include <osmocom/gsm/gsm23003.h>

struct sgsn_instance;
@@ -16,18 +17,35 @@
struct llist_head ra_list;
};

+enum sgsn_ra_ran_type {
+ RA_TYPE_GERAN_Gb,
+ RA_TYPE_UTRAN_Iu,
+};
+
+extern const struct value_string sgsn_ra_ran_type_names[];
+
struct sgsn_ra {
/* Entry in sgsn_ra_global->ra_list */
struct llist_head list;

struct osmo_routing_area_id rai;
- /* cells contains a list of sgsn_ra_cells which are alive */
- struct llist_head cells;
-};

-enum sgsn_ra_ran_type {
- RA_TYPE_GERAN_Gb,
- RA_TYPE_UTRAN_Iu,
+ /* For GERAN: every PCU is connected to the SGSN. It allows the SGSN to know every single cell.
+ * For routing, the SGSN must know to which PCU a given cell is connected.
+ * It is possible that more than one PCU serves the same Routing Area.
+ *
+ * For UTRAN: only the RNC (HNB via HNBGW) is communicating with the SGSN.
+ * The SGSN doesn't know every cell, because they aren't accepted individually by the SGSN.
+ * The SGSN only "knows" RAI/SAI if they have been used. In the future it would be a good idea to
+ * allow configuring RA in the vty/config as well.
+ * Similar to the GERAN Cell, but iu_client doesn't notify us for every given SAI, only for RAC.
+ * Further the SGSN doesn't get informed about Service Area and can't relate the SAI to a given UE.
+ * For UTRAN only do a LAC/RAC <> RNC relation and don't have a specific cell relation.
+ */
+ enum sgsn_ra_ran_type ran_type;
+
+ /* GERAN/UTRAN: cells contains a list of sgsn_ra_cells which are alive */
+ struct llist_head cells_alive_list;
};

struct sgsn_ra_cell {
@@ -55,7 +73,7 @@

void sgsn_ra_init(struct sgsn_instance *inst);

-struct sgsn_ra *sgsn_ra_alloc(const struct osmo_routing_area_id *rai);
+struct sgsn_ra *sgsn_ra_alloc(const struct osmo_routing_area_id *rai, enum sgsn_ra_ran_type ran_type);
void sgsn_ra_free(struct sgsn_ra *ra);
struct sgsn_ra_cell *sgsn_ra_cell_alloc_geran(struct sgsn_ra *ra, uint16_t cell_id, uint16_t nsei, uint16_t bvci);
void sgsn_ra_cell_free(struct sgsn_ra_cell *cell);
@@ -72,6 +90,7 @@
struct sgsn_ra_cell *sgsn_ra_get_cell_by_ra(const struct sgsn_ra *ra, uint16_t cell_id);
struct sgsn_ra_cell *sgsn_ra_get_cell_by_gb(uint16_t nsei, uint16_t bvci);
struct sgsn_ra *sgsn_ra_get_ra(const struct osmo_routing_area_id *ra_id);
+struct sgsn_ra *sgsn_ra_get_ra_geran(const struct osmo_routing_area_id *ra_id);


/*
diff --git a/src/sgsn/gprs_routing_area.c b/src/sgsn/gprs_routing_area.c
index 67b15ae..e215a68 100644
--- a/src/sgsn/gprs_routing_area.c
+++ b/src/sgsn/gprs_routing_area.c
@@ -23,6 +23,7 @@
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/rate_ctr.h>
+#include <osmocom/core/utils.h>
#include <osmocom/gsm/gsm48.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/gprs_bssgp.h>
@@ -31,6 +32,12 @@

#include <osmocom/sgsn/gprs_routing_area.h>

+const struct value_string sgsn_ra_ran_type_names[] = {
+ { RA_TYPE_GERAN_Gb, "GERAN_Gb" },
+ { RA_TYPE_UTRAN_Iu, "UTRAN_Iu" },
+ { 0, NULL },
+};
+
static void _sgsn_ra_cell_free(struct sgsn_ra_cell *cell, bool drop_empty_ra)
{
struct sgsn_ra *ra;
@@ -48,7 +55,7 @@
ra = cell->ra;
talloc_free(cell);

- if (llist_empty(&ra->cells))
+ if (llist_empty(&ra->cells_alive_list))
sgsn_ra_free(ra);
}

@@ -64,7 +71,7 @@
if (!ra)
return;

- llist_for_each_entry_safe(cell, cell2, &ra->cells, list) {
+ llist_for_each_entry_safe(cell, cell2, &ra->cells_alive_list, list) {
_sgsn_ra_cell_free(cell, false);
}

@@ -72,15 +79,16 @@
talloc_free(ra);
}

-struct sgsn_ra *sgsn_ra_alloc(const struct osmo_routing_area_id *rai)
+struct sgsn_ra *sgsn_ra_alloc(const struct osmo_routing_area_id *rai, enum sgsn_ra_ran_type ran_type)
{
struct sgsn_ra *ra;
ra = talloc_zero(sgsn->routing_area, struct sgsn_ra);
if (!ra)
return NULL;

- INIT_LLIST_HEAD(&ra->cells);
+ INIT_LLIST_HEAD(&ra->cells_alive_list);
ra->rai = *rai;
+ ra->ran_type = ran_type;
llist_add(&ra->list, &sgsn->routing_area->ra_list);
return ra;
}
@@ -99,7 +107,7 @@
cell->u.geran.bvci = bvci;
cell->u.geran.nsei = nsei;

- llist_add(&cell->list, &ra->cells);
+ llist_add(&cell->list, &ra->cells_alive_list);

return cell;
}
@@ -115,6 +123,19 @@
return NULL;
}

+struct sgsn_ra *sgsn_ra_get_ra_geran(const struct osmo_routing_area_id *ra_id)
+{
+ struct sgsn_ra *ra = sgsn_ra_get_ra(ra_id);
+
+ if (!ra)
+ return ra;
+
+ if (ra->ran_type == RA_TYPE_GERAN_Gb)
+ return ra;
+
+ return NULL;
+}
+
struct sgsn_ra_cell *sgsn_ra_get_cell_by_gb(uint16_t nsei, uint16_t bvci)
{
struct sgsn_ra *ra;
@@ -125,7 +146,10 @@
return NULL;

llist_for_each_entry(ra, &sgsn->routing_area->ra_list, list) {
- llist_for_each_entry(cell, &ra->cells, list) {
+ if (ra->ran_type != RA_TYPE_GERAN_Gb)
+ continue;
+
+ llist_for_each_entry(cell, &ra->cells_alive_list, list) {
if (cell->ran_type != RA_TYPE_GERAN_Gb)
continue;

@@ -144,7 +168,7 @@

OSMO_ASSERT(cb);

- llist_for_each_entry_safe(cell, tmp, &ra->cells, list) {
+ llist_for_each_entry_safe(cell, tmp, &ra->cells_alive_list, list) {
ret = cb(cell, cb_data);
switch (ret) {
case SGSN_RA_CB_CONT:
@@ -174,11 +198,15 @@
return sgsn_ra_foreach_cell(ra, cb, cb_data);
}

+/* valid for GERAN */
struct sgsn_ra_cell *sgsn_ra_get_cell_by_ra(const struct sgsn_ra *ra, uint16_t cell_id)
{
struct sgsn_ra_cell *cell;

- llist_for_each_entry(cell, &ra->cells, list) {
+ if (ra->ran_type != RA_TYPE_GERAN_Gb)
+ return NULL;
+
+ llist_for_each_entry(cell, &ra->cells_alive_list, list) {
if (cell->cell_id == cell_id)
return cell;
}
@@ -186,6 +214,7 @@
return NULL;
}

+/* valid for GERAN */
struct sgsn_ra_cell *sgsn_ra_get_cell_by_lai(const struct osmo_location_area_id *lai, uint16_t cell_id)
{
struct sgsn_ra *ra;
@@ -194,10 +223,13 @@
/* This is a little bit in-efficient. A more performance way, but more complex would
* adding a llist for LAC on top of the routing areas */
llist_for_each_entry(ra, &sgsn->routing_area->ra_list, list) {
+ if (ra->ran_type != RA_TYPE_GERAN_Gb)
+ continue;
+
if (osmo_lai_cmp(&ra->rai.lac, lai) != 0)
continue;

- llist_for_each_entry(cell, &ra->cells, list) {
+ llist_for_each_entry(cell, &ra->cells_alive_list, list) {
if (cell->cell_id == cell_id)
return cell;
}
@@ -206,7 +238,7 @@
return NULL;
}

-/*! Return the cell by searching for the RA, when found, search the cell within the RA
+/*! Return the GERAN cell by searching for the RA, when found, search the cell within the RA
*
* \param cgi_ps
* \return the cell or NULL if not found
@@ -217,7 +249,7 @@

OSMO_ASSERT(cgi_ps);

- ra = sgsn_ra_get_ra(&cgi_ps->rai);
+ ra = sgsn_ra_get_ra_geran(&cgi_ps->rai);
if (!ra)
return NULL;

@@ -246,9 +278,10 @@
OSMO_ASSERT(cgi_ps);

/* TODO: do we have to move all MS to GMM IDLE state when this happens for a alive cell which got reseted? */
- ra = sgsn_ra_get_ra(&cgi_ps->rai);
+ ra = sgsn_ra_get_ra_geran(&cgi_ps->rai);
if (!ra) {
- ra = sgsn_ra_alloc(&cgi_ps->rai);
+ /* TODO: check for UTRAN rai when introducing UTRAN support */
+ ra = sgsn_ra_alloc(&cgi_ps->rai, RA_TYPE_GERAN_Gb);
if (!ra)
return -ENOMEM;
ra_created = true;
@@ -312,7 +345,10 @@
bool found = false;

llist_for_each_entry_safe(ra, ra2, &sgsn->routing_area->ra_list, list) {
- llist_for_each_entry_safe(cell, cell2, &ra->cells, list) {
+ if (ra->ran_type != RA_TYPE_GERAN_Gb)
+ continue;
+
+ llist_for_each_entry_safe(cell, cell2, &ra->cells_alive_list, list) {
if (cell->ran_type != RA_TYPE_GERAN_Gb)
continue;

@@ -322,9 +358,8 @@
}
}

- if (llist_empty(&ra->cells))
+ if (llist_empty(&ra->cells_alive_list))
sgsn_ra_free(ra);
-
}

return found ? 0 : -ENOENT;
@@ -338,11 +373,11 @@

rate_ctr_inc(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_PAGING_PS));

- ra = sgsn_ra_get_ra(ra_id);
+ ra = sgsn_ra_get_ra_geran(ra_id);
if (!ra)
return -ENOENT;

- llist_for_each_entry(cell, &ra->cells, list) {
+ llist_for_each_entry(cell, &ra->cells_alive_list, list) {
if (cell->ran_type == RA_TYPE_GERAN_Gb) {
sgsn_bssgp_page_ps_bvci(mmctx, cell->u.geran.nsei, cell->u.geran.bvci);
ret = 0;
diff --git a/tests/gprs_routing_area/gprs_routing_area_test.c b/tests/gprs_routing_area/gprs_routing_area_test.c
index e1aec0f..f1d5c16 100644
--- a/tests/gprs_routing_area/gprs_routing_area_test.c
+++ b/tests/gprs_routing_area/gprs_routing_area_test.c
@@ -75,7 +75,7 @@
printf("Testing Routing Area create/free\n");

sgsn = sgsn_instance_alloc(tall_sgsn_ctx);
- ra = sgsn_ra_alloc(&raid);
+ ra = sgsn_ra_alloc(&raid, RA_TYPE_GERAN_Gb);
OSMO_ASSERT(ra);
OSMO_ASSERT(llist_count(&sgsn->routing_area->ra_list) == 1);

@@ -105,26 +105,26 @@
printf("Testing Routing Area create/free\n");

sgsn = sgsn_instance_alloc(tall_sgsn_ctx);
- ra = sgsn_ra_alloc(&raid);
+ ra = sgsn_ra_alloc(&raid, RA_TYPE_GERAN_Gb);
OSMO_ASSERT(ra);
OSMO_ASSERT(llist_count(&sgsn->routing_area->ra_list) == 1);

cell_a = sgsn_ra_cell_alloc_geran(ra, cell_id, nsei, bvci);
OSMO_ASSERT(cell_a);
OSMO_ASSERT(llist_count(&sgsn->routing_area->ra_list) == 1);
- OSMO_ASSERT(llist_count(&ra->cells) == 1);
+ OSMO_ASSERT(llist_count(&ra->cells_alive_list) == 1);

sgsn_ra_free(ra);
OSMO_ASSERT(llist_empty(&sgsn->routing_area->ra_list));

- ra = sgsn_ra_alloc(&raid);
+ ra = sgsn_ra_alloc(&raid, RA_TYPE_GERAN_Gb);
OSMO_ASSERT(ra);
OSMO_ASSERT(llist_count(&sgsn->routing_area->ra_list) == 1);

cell_a = sgsn_ra_cell_alloc_geran(ra, cell_id, nsei, bvci);
OSMO_ASSERT(cell_a);
OSMO_ASSERT(llist_count(&sgsn->routing_area->ra_list) == 1);
- OSMO_ASSERT(llist_count(&ra->cells) == 1);
+ OSMO_ASSERT(llist_count(&ra->cells_alive_list) == 1);

sgsn_ra_free(ra);
OSMO_ASSERT(llist_empty(&sgsn->routing_area->ra_list));
@@ -160,7 +160,7 @@
printf("Testing Routing Area find\n");

sgsn = sgsn_instance_alloc(tall_sgsn_ctx);
- ra_a = sgsn_ra_alloc(&ra_id);
+ ra_a = sgsn_ra_alloc(&ra_id, RA_TYPE_GERAN_Gb);
OSMO_ASSERT(ra_a);
OSMO_ASSERT(llist_count(&sgsn->routing_area->ra_list) == 1);

@@ -194,7 +194,7 @@
cgi.cell_identity = cell_id_not_found;
cgi_ps.cell_identity = cell_id_not_found;

- ra_a = sgsn_ra_alloc(&ra_id);
+ ra_a = sgsn_ra_alloc(&ra_id, RA_TYPE_GERAN_Gb);
OSMO_ASSERT(ra_a);
OSMO_ASSERT(llist_count(&sgsn->routing_area->ra_list) == 1);

@@ -263,14 +263,14 @@
printf("Testing Routing Area BSSGP BVC RESET IND\n");

sgsn = sgsn_instance_alloc(tall_sgsn_ctx);
- ra_a = sgsn_ra_alloc(&ra_id);
+ ra_a = sgsn_ra_alloc(&ra_id, RA_TYPE_GERAN_Gb);
OSMO_ASSERT(ra_a);
OSMO_ASSERT(llist_count(&sgsn->routing_area->ra_list) == 1);
- OSMO_ASSERT(llist_count(&ra_a->cells) == 0);
+ OSMO_ASSERT(llist_count(&ra_a->cells_alive_list) == 0);

rc = sgsn_ra_bvc_reset_ind(nsei, bvci, &cgi_ps);
OSMO_ASSERT(rc == 0);
- OSMO_ASSERT(llist_count(&ra_a->cells) == 1);
+ OSMO_ASSERT(llist_count(&ra_a->cells_alive_list) == 1);

cell_a = sgsn_ra_get_cell_by_cgi(&cgi);
OSMO_ASSERT(cell_a);
@@ -324,7 +324,7 @@
OSMO_ASSERT(rc == 0);

ra_a = sgsn_ra_get_ra(&cgi_ps.rai);
- OSMO_ASSERT(llist_count(&ra_a->cells) == 1);
+ OSMO_ASSERT(llist_count(&ra_a->cells_alive_list) == 1);

rc = sgsn_ra_nsei_failure_ind(nsei);
OSMO_ASSERT(rc == 0);

To view, visit change 40688. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-MessageType: merged
Gerrit-Project: osmo-sgsn
Gerrit-Branch: master
Gerrit-Change-Id: I59c35f1a4912ff11574bb31e4fe424816993548c
Gerrit-Change-Number: 40688
Gerrit-PatchSet: 3
Gerrit-Owner: lynxis lazus <lynxis@fe80.eu>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: daniel <dwillmann@sysmocom.de>
Gerrit-Reviewer: lynxis lazus <lynxis@fe80.eu>
Gerrit-Reviewer: pespin <pespin@sysmocom.de>
Gerrit-CC: fixeria <vyanitskiy@sysmocom.de>