UE state leak: when HNB re-registers, discard previous UE state

User reports show leaked UE contexts over time, in a scenario where HNB
regularly disconnect and reconnect.

So far, when we receive a HNB REGISTER REQ, we log as "duplicated" and
continue to use the hnb_context unchanged. But it seems obvious that a
HNB that registers does not expect any UE state to remain. It will
obviously not tear down UE contexts (HNBAP or RUA) that have been
established before the HNB REGISTER REQUEST. These hence remain in
osmo-hnbgw indefinitely.

When receiving a HNB REGISTER REQUEST, release all its previous UE
state. Allow the HNB to register with a clean slate.

The aim is to alleviate the observed build-up of apparently orphaned UE
contexts, in order to avoid gradual memory exhaustion.

Related: SYS#6297
Change-Id: I7fa8a04cc3b2dfba263bda5b410961c77fbed332
This commit is contained in:
Neels Hofmeyr 2023-02-11 01:54:50 +01:00
parent a3c7f750a2
commit 8eefcbee92
3 changed files with 21 additions and 7 deletions

View File

@ -188,6 +188,7 @@ void ue_context_free(struct ue_context *ue);
struct hnb_context *hnb_context_alloc(struct hnb_gw *gw, struct osmo_stream_srv_link *link, int new_fd);
void hnb_context_release(struct hnb_context *ctx);
void hnb_context_release_ue_state(struct hnb_context *ctx);
void hnbgw_vty_init(struct hnb_gw *gw, void *tall_ctx);
int hnbgw_vty_go_parent(struct vty *vty);

View File

@ -395,15 +395,10 @@ const char *hnb_context_name(struct hnb_context *ctx)
return umts_cell_id_name(&ctx->id);
}
void hnb_context_release(struct hnb_context *ctx)
void hnb_context_release_ue_state(struct hnb_context *ctx)
{
struct hnbgw_context_map *map, *map2;
LOGHNB(ctx, DMAIN, LOGL_INFO, "Releasing HNB context\n");
/* remove from the list of HNB contexts */
llist_del(&ctx->list);
/* deactivate all context maps */
llist_for_each_entry_safe(map, map2, &ctx->map_list, hnb_list) {
/* remove it from list, as HNB context will soon be
@ -414,6 +409,16 @@ void hnb_context_release(struct hnb_context *ctx)
context_map_deactivate(map);
}
ue_context_free_by_hnb(ctx->gw, ctx);
}
void hnb_context_release(struct hnb_context *ctx)
{
LOGHNB(ctx, DMAIN, LOGL_INFO, "Releasing HNB context\n");
/* remove from the list of HNB contexts */
llist_del(&ctx->list);
hnb_context_release_ue_state(ctx);
if (ctx->conn) { /* we own a conn, we must free it: */
LOGHNB(ctx, DMAIN, LOGL_INFO, "Closing HNB SCTP connection %s\n",

View File

@ -467,7 +467,15 @@ static int hnbgw_rx_hnb_register_req(struct hnb_context *ctx, ANY_t *in)
LOGHNB(ctx, DHNBAP, LOGL_DEBUG, "HNB-REGISTER-REQ %s MCC=%u,MNC=%u,LAC=%u,RAC=%u,SAC=%u,CID=%u from %s%s\n",
ctx->identity_info, ctx->id.mcc, ctx->id.mnc, ctx->id.lac, ctx->id.rac, ctx->id.sac, ctx->id.cid,
name, ctx->hnb_registered ? " (duplicated)" : "");
name, ctx->hnb_registered ? " (re-connecting)" : "");
if (ctx->hnb_registered) {
/* The HNB is already registered, and we are seeing a new HNB Register Request. The HNB has restarted
* without us noticing. Clearly, the HNB does not expect any UE state to be active here, so discard any
* UE contexts and SCCP connections associated with this HNB. */
LOGHNB(ctx, DHNBAP, LOGL_NOTICE, "HNB reconnecting, discarding all previous UE state\n");
hnb_context_release_ue_state(ctx);
}
ctx->hnb_registered = true;