Refactor the entire RUA <-> SCCP connection-oriented message forwarding:
- conquer confusion about hnbgw_context_map release behavior, and
- eradicate SCCP connection leaks.
Finer points:
== Context map state ==
So far, we had a single context map state and some flags to keep track
of both the RUA and the SCCP connections. It was easy to miss connection
cleanup steps, especially on the SCCP side.
Instead, the two FSMs clearly define the RUA and SCCP conn states
separately, and each side takes care of its own release needs for all
possible scenarios.
- When both RUA and SCCP are released, the context map is discarded.
- A context map can stay around to wait for proper SCCP release, even if
the RUA side has lost the HNB connection.
- Completely drop the async "context mapper garbage collection", because
the FSMs clarify the release and free steps, synchronously.
- We still keep a (simplified) enum for global context map state, but
this is only used so that VTY reporting remains mostly unchanged.
== Context map cleanup confusion ==
The function context_map_hnb_released() was the general cleanup function
for a context map. Instead, add separate context_map_free().
== Free context maps separately from HNB ==
When a HNB releases, talloc_steal() the context maps out of the HNB
specific hnb_ctx, so that they are not freed along with the HNB state,
possibly leaving SCCP connections afloat.
(It is still nice to normally keep context maps as talloc children of
their respective hnb_ctx, so talloc reports show which belongs to
which.)
So far, context map handling found the global hnb_gw pointer via
map->hnb_ctx->gw. But in fact, a HNB may disappear at any point in time.
Instead, use a separate hnb_gw pointer in map->gw.
== RUA procedure codes vs. SCCP prims ==
So far, the RUA rx side composed SCCP prims to pass on:
RUA rx ---SCCP-prim--> RANAP handling ---SCCP-prim--> SCCP tx
That is a source of confusion: a RUA procedure code should not translate
1:1 to SCCP prims, especially for RUA id-Disconnect (see release charts
below).
Instead, move SCCP prim composition over to the SCCP side, using FSM
events to forward:
RUA rx --event--> RUA FSM --event--> SCCP FSM --SCCP-prim--> SCCP tx
+RANAP +RANAP +RANAP
RUA tx <--RUA---- RUA FSM <--event-- SCCP FSM <--event-- SCCP rx
+RANAP +RANAP +RANAP
Hence choose the correct prim according to the SCCP FSM state.
- in hnbgw_rua.c, use RUA procedure codes, not prim types.
- via the new FSM events' data args, pass msgb containing RANAP PDUs.
== Fix SCCP Release behavior ==
So far, the normal conn release behavior was
HNB HNBGW CN
| --id-Disconnect--> | ---SCCP-Released--> | Iu-ReleaseComplete
| | <--SCCP-RLC-------- | (no data)
Instead, the SCCP release is now in accordance with 3GPP TS 48.006 9.2
'Connection release':
The MSC sends a SCCP released message. This message shall not contain
any user data field.
i.e.:
HNB HNBGW CN
| --id-Disconnect--> | ---Data-Form-1(!)--> | Iu-ReleaseComplete
| | <--SCCP-Released---- | (no data)
| | ---SCCP-RLC--------> | (no data)
(Side note, the final SCCP Release Confirm step is taken care of
implicitly by libosmo-sigtran's sccp_scoc.c FSM.)
If the CN fails to respond with SCCP-Released, on new X31 timeout,
osmo-hnbgw will send an SCCP Released to the CN as fallback.
== Memory model for message dispatch ==
So far, an osmo_scu_prim aka "oph" was passed between RUA and SCCP
handling code, and the final dispatch freed it. Every error path had to
take care not to leak any oph.
Instead, use a much easier and much more leakage proof memory model,
inspired by fixeria:
- on rx, dispatch RANAP msgb that live in OTC_SELECT.
- no code path needs to msgb_free() -- the msgb is discarded via
OTC_SELECT when handling is done, error or no error.
- any code path may also choose to store the msgb for async dispatch,
using talloc_steal(). The user plane mapping via MGW and UPF do that.
- if any code path does msgb_free(), that would be no problem either
(but none do so now, for simplicity).
== Layer separation ==
Dispatch *all* connection-oriented RUA tx via the RUA FSM and SCCP tx
via the SCCP FSM, do not call rua_tx_dt() or osmo_sccp_user_sap_down()
directly.
== Memory model for decoded ranap_message IEs ==
Use a talloc destructor to make sure that the ranap_message IEs are
always implicitly freed upon talloc_free(), so that no code path can
possibly forget to do so.
== Implicit cleanup by talloc ==
Use talloc scoping to remove a bunch of explicit cleanup code. For
example, make a chached message a talloc child of its handler:
talloc_steal(mgw_fsm_priv, message);
mgw_fsm_priv->ranap_rab_ass_req_message = message;
and later implicitly free 'message' by only freeing the handler:
talloc_free(mgw_fsm_priv)
Related: SYS#6297
Change-Id: I6ff7e36532ff57c6f2d3e7e419dd22ef27dafd19
Rename context_map_deactivate() to context_map_hnb_released().
This function is called only when the HNB is released / lost.
Change-Id: I6dcb26c94558fff28faf8f823e490967a9baf2ec
The SCCP CR payload length limit is now implemented in libosmo-sigtran
v1.7.0. The limit no longer needs to be enforced in osmo-hnbgw.
This reverts commit 2c91bd66a1,
except for keeping the cfg option, marked deprecated, and not doing
anything.
Fixes: OS#5906
Related: SYS#5968
Related: OS#5579
Depends: I174b2ce06a31daa5a129c8a39099fe8962092df8 (osmo-ttcn3-hacks)
Change-Id: I18dece84b33bbefce8617fbb0b2d79a7e5adb263
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
Large RAN installations may benefit from distributing the RTP voice
stream load over multiple media gateways.
libosmo-mgcp-client supports MGW pooling since version 1.8.0 (more than
one year ago). OsmoBSC has already been making use of it since then (see
osmo-bsc.git 8d22e6870637ed6d392a8a77aeaebc51b23a8a50); lets use this
feature in osmo-hngw too.
This commit is also part of a series of patches cleaning up
libosmo-mgcp-client and slowly getting rid of the old non-mgw-pooled VTY
configuration, in order to keep only 1 way to configure
libosmo-mgcp-client through VTY.
Related: SYS#5091
Related: SYS#5987
Change-Id: I371dc773b58788ee21037dc25d77f556c89c6b61
Otherwise the libosmo-netif stream API may continue accessing the conn
after returning if the socket has the WRITE flag active in the same main
loop iteration.
Change-Id: I628c59a88d94d299f432f405b37fbe602381d47e
It was seen on a real pcap trace (sctp & gsmtap_log) that the kernel
stack may decide to kill the connection (sending an ABORT) if it fails
to transmit some data after a while:
ABORT Cause code: "Protocol violation (0x000d)",
Cause Information: "Association exceeded its max_retrans count".
When this occurs, the kernel sends the
MSG_NOTIFICATION,SCTP_ASSOC_CHANGE,SCTP_COMM_LOST notification when
reading from the socket with sctp_recvmsg(). This basically signals that
the socket conn is dead, and subsequent writes to it will result in
send() failures (and receive SCTP_SEND_FAILED notification upon follow
up reads).
It's important to notice that after those events, there's no other sort
of different event like SHUTDOWN coming in, so that's the time at which
we must tell the user to close the socket.
Hence, let's signal the caller that the socket is dead by returning 0,
to comply with usual recv() API.
Related: SYS#6113
Change-Id: If35efd404405f926a4a6cc45862eeadd1b04e08c
SCTP_SHUTDOWN_EVENT is a first class event, and not a subtype of
SCTP_ASSOC_CHANGE (such as SCTP_SHUTDOWN_COMP).
Related: SYS#6113
Change-Id: I7fa648142c07f63c55091d2a15b9d7312bcd4cec
Before handling of OSMO_STREAM_SCTP_MSG_FLAGS_NOTIFICATION in recent
commit (see Fixes: below), osmo_stream_srv_recv() and
internal _sctp_recvmsg_wrapper() in libosmo-netif would return either
-EAGAIN or 0 when an sctp notification was received from the kernel.
After adding handling of OSMO_STREAM_SCTP_MSG_FLAGS_NOTIFICATION, the
code paths for "rc == -EAGAIN" and "rc == 0" would not be executed
anymore since the first branch takes preference in the if-else
tree. For "rc == -EAGAIN" it's fine because the new branch superseeds
what's done on the "rc == -EAGAIN" branch. However, for the "rc == 0",
we forgot to actually destroy the connection. The "rc == 0" branch was
basically reached when SCTP_SHUTDOWN_EVENT was received because
osmo_stream_srv_recv() tried to resemble the interface of regular
recv(); let's hence check for that explicitly and destroy the conn
object (and the related hnb context in the process) when we receive
that event.
Fixes: 1de2091515
Related: SYS#6113
Change-Id: I11b6af51a58dc250975a696b98d0c0c9ff3df9e0
Sometimes an hNodeB may reconnect (SCTP INIT) using same SCTP tuple without
closing the previous conn. This is handled by the SCTP stack by means of
pushing a RESET notification up the stack to the sctp_recvmsg() user.
Let's handle this by marking the HNB as unregistered, since most
probably a HNB Register Req comes next as the upper layer state is
considered lost.
Depends: libosmo-netif.git Change-Id I0ee94846a15a23950b9d70eaaef1251267296bdd
Related: SYS#6113
Change-Id: Ib22881b1a34b1c3dd350912b3de8904917cf34ef
Otherwise, some paths calling hnb_context_release() (like failing to
transmit HNB-REGISTER-REJECT) would end up with a conn object alive with
no assigned hnb_context, which is something not wanted.
This way an alive conn object always has an associated hnb_context, and
they are only disassociated during synchronous release path.
Related: OS#5676
Change-Id: I44fea7ec74f14e0458861c92da4acf685ff695c1
It was observed that under some circumstances (after HNBAP
HNB-De-Register) we end up crashing because a connection has no HNB
assigned to it. Let's explicitly assert if that happens, in order
clarify and avoid same sort of thing happening without clear view on
what's going on.
The issue will be fixed in a follow-up patch.
Closes: OS#5676
Change-Id: I1eedab6f3ac974e942b02eaae41556f87dd8b6ba
* Use osmo_stream closed_cb to call hnb_context_release() in all cases
* Also call hnbap_free_hnbregisterrequesties() when sending hnb register
reject
Related: OS#5656
Change-Id: I3ba02b0939413c67bc8088ea1a8f2252fc2bda31
It is reported that a third-party SGSN is rejecting SCCP CR when the
SCCP message part exceeds a certain length. The solution is to first
send an SCCP CR without payload, and send the payload in a DT later.
Add config option
hnbgw
sccp cr max-payload-len <0-999999>
If the RANAP payload surpasses the given length, osmo-hnbgw will first
send an SCCP CR without payload, cache the RANAP payload, and put that
in an SCCP DT once the SCCP CC is received.
The original idea was to limit the size of the entire SCCP part of the
message, but I'm currently not sure how to determine that without
copying much of the osmo_sccp code. I figured using a limit on the RANAP
payload is sufficient. To avoid the error with above third-party SGSN,
the easy solution is to set max-payload-len to 0, so that we always get
a separate SCCP CR without payload.
Related: SYS#5968
Related: I827e081eaacfb8e76684ed1560603e6c8f896c38 (osmo-ttcn3-hacks)
Change-Id: If0c5c0a76e5230bf22871f527dcb2dbdf34d7328
Upcoming patch adds to this function. Let me first combine those four
LOGP() to a single one, use proper osmo_sccp_addr_to_str_c(OTC_SELECT).
To be able to use OTC_SELECT, switch hnbgw.c to osmo_select_main_ctx().
Related: SYS#5968
Change-Id: I1e0ea0a883e8cf65e6cfb45ed9b6f3d8fb7c59eb
osmo-hnbgw lacks support for an co-located media gateway. This makes it
virtually impossible to isolate the HNB from the core network properly.
Lets add MGCP support to osmo-hnbgw so that it can control a co-located
media gateway to relay the RTP streams between HNB and core network.
Change-Id: Ib9b62e0145184b91c56ce5d8870760bfa49cc5a4
Related: OS#5152