lynxis lazus has submitted this change. ( https://gerrit.osmocom.org/c/osmo-sgsn/+/40688?usp=email )
Change subject: routing area: introduce ran_type on the RA ......................................................................
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(-)
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
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);