Introduce support for libosmo-mgcp-client MGW pooling

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-msc 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: I7670ba56fe989706579224a364595fdd4b4708ff
This commit is contained in:
Pau Espin 2022-10-17 18:09:15 +02:00
parent f009aea963
commit ccbd412512
11 changed files with 100 additions and 28 deletions

View File

@ -12,10 +12,11 @@ network
encryption a5 0
rrlp mode none
mm info 1
mgw 0
mgw remote-ip 127.0.0.1
mgw remote-port 2427
mgw local-port 2728
msc
mgw remote-ip 127.0.0.1
mgw remote-port 2427
mgw local-port 2728
assign-tmsi
auth-tuple-max-reuse-count 3
auth-tuple-reuse-on-error 1

View File

@ -12,6 +12,10 @@ network
encryption a5 0
rrlp mode none
mm info 1
mgw 0
mgw remote-ip 127.0.0.1
mgw remote-port 2427
mgw local-port 2728
cs7 instance 0
point-code 0.23.1
asp asp-clnt-OsmoMSC-A-Iu 2905 0 m3ua
@ -21,7 +25,4 @@ cs7 instance 0
msc
cs7-instance-a 0
cs7-instance-iu 0
mgw remote-ip 127.0.0.1
mgw remote-port 2427
mgw local-port 2728
assign-tmsi

View File

@ -12,6 +12,10 @@ network
encryption a5 0
rrlp mode none
mm info 1
mgw 0
mgw remote-ip 127.0.0.1
mgw remote-port 2427
mgw local-port 2728
cs7 instance 0
point-code 0.23.1
asp asp-clnt-OsmoMSC-A 2905 0 m3ua
@ -23,7 +27,4 @@ cs7 instance 1
msc
cs7-instance-a 0
cs7-instance-iu 1
mgw remote-ip 127.0.0.1
mgw remote-port 2427
mgw local-port 2728
assign-tmsi

View File

@ -149,11 +149,23 @@ default port for MGCP (2427) on local host (127.0.0.1).
Here is an example configuration for a remote MGW:
----
msc
mgw remote-ip 10.9.8.7
mgw remote-port 2427
mgw reset-endpoint rtpbridge/* <1>
network
mgw 0
mgw remote-ip 10.9.8.7
mgw remote-port 2427
mgw reset-endpoint rtpbridge/* <1>
----
<1> The 'reset-endpoint' setting instructs the OsmoMGW to send a wildcarded
DLCX to the media gateway. This helps to clear lingering calls from the
media gateway when the OsmoMSC is restarted.
[NOTE]
====
Previous versions of OsmoMSC (1.9.0 and below) didn't have the 'mgw' VTY node and
hence didn't support the MGW pooling feature. Therefore, historically the MGW
related commands where placed under the `msc` VTY node. The MGW related commands
under the `msc` VTY are still parsed and used but its use is deprecated and
hence discouraged in favour of the new `mgw` node. Writing the config to a file
from within OsmoMSC will automatically convert the config to use the new `mgw`
node.
====

View File

@ -16,6 +16,7 @@
#include <osmocom/crypt/utran_cipher.h>
#include <osmocom/mgcp_client/mgcp_client.h>
#include <osmocom/mgcp_client/mgcp_client_pool.h>
#include <osmocom/msc/msc_common.h>
#include <osmocom/msc/neighbor_ident.h>
@ -216,7 +217,9 @@ struct gsm_network {
struct {
struct osmo_tdef *tdefs;
struct mgcp_client_conf conf;
struct mgcp_client *client;
/* MGW pool, also includes the single MGCP client as fallback if no
* pool is configured. */
struct mgcp_client_pool *mgw_pool;
} mgw;
struct {

View File

@ -17,6 +17,7 @@ extern struct cmd_element cfg_no_description_cmd;
enum bsc_vty_node {
GSMNET_NODE = _LAST_OSMOVTY_NODE + 1,
MGW_NODE,
SUBSCR_NODE,
MSC_NODE,
MNCC_INT_NODE,

View File

@ -122,7 +122,13 @@ void call_leg_release(struct call_leg *cl)
static void call_leg_mgw_endpoint_gone(struct call_leg *cl)
{
struct mgcp_client *mgcp_client;
int i;
/* Put MGCP client back into MGW pool */
mgcp_client = osmo_mgcpc_ep_client(cl->mgw_endpoint);
mgcp_client_pool_put(mgcp_client);
cl->mgw_endpoint = NULL;
for (i = 0; i < ARRAY_SIZE(cl->rtp); i++) {
if (!cl->rtp[i])
@ -275,10 +281,17 @@ int call_leg_ensure_rtp_alloc(struct call_leg *cl, enum rtp_direction dir, uint3
if (cl->rtp[dir])
return 0;
if (!cl->mgw_endpoint)
if (!cl->mgw_endpoint) {
struct mgcp_client *mgcp_client = mgcp_client_pool_get(gsmnet->mgw.mgw_pool);
if (!mgcp_client) {
LOG_CALL_LEG(cl, LOGL_ERROR,
"cannot ensure MGW endpoint -- no MGW configured, check configuration!\n");
return -ENODEV;
}
cl->mgw_endpoint = osmo_mgcpc_ep_alloc(cl->fi, CALL_LEG_EV_MGW_ENDPOINT_GONE,
gsmnet->mgw.client, gsmnet->mgw.tdefs, cl->fi->id,
"%s", mgcp_client_rtpbridge_wildcard(gsmnet->mgw.client));
mgcp_client, gsmnet->mgw.tdefs, cl->fi->id,
"%s", mgcp_client_rtpbridge_wildcard(mgcp_client));
}
if (!cl->mgw_endpoint) {
LOG_CALL_LEG(cl, LOGL_ERROR, "failed to setup MGW endpoint\n");
return -EIO;

View File

@ -2033,6 +2033,8 @@ void msc_vty_init(struct gsm_network *msc_network)
install_element(GSMNET_NODE, &cfg_net_no_per_loc_upd_cmd);
install_element(GSMNET_NODE, &cfg_net_call_wait_cmd);
install_element(GSMNET_NODE, &cfg_net_no_call_wait_cmd);
mgcp_client_pool_vty_init(GSMNET_NODE, MGW_NODE, " ", msc_network->mgw.mgw_pool);
install_element(CONFIG_NODE, &cfg_msc_cmd);
install_node(&msc_node, config_write_msc);
@ -2066,7 +2068,9 @@ void msc_vty_init(struct gsm_network *msc_network)
/* Timer configuration commands (generic osmo_tdef API) */
osmo_tdef_vty_groups_init(MSC_NODE, msc_tdef_group);
/* Deprecated: Old MGCP config without pooling support in MSC node: */
mgcp_client_vty_init(msc_network, MSC_NODE, &msc_network->mgw.conf);
#ifdef BUILD_IU
ranap_iu_vty_init(MSC_NODE, (enum ranap_nsap_addr_enc*)&msc_network->iu.rab_assign_addr_enc);
#endif

View File

@ -256,6 +256,7 @@ struct gsm_network *msc_network_alloc(void *ctx,
MSC_HLR_REMOTE_IP_DEFAULT);
net->gsup_server_port = MSC_HLR_REMOTE_PORT_DEFAULT;
net->mgw.mgw_pool = mgcp_client_pool_alloc(net);
mgcp_client_conf_init(&net->mgw.conf);
net->call_waiting = true;
net->lcls_permitted = false;
@ -546,6 +547,41 @@ extern void *tall_gsms_ctx;
extern void *tall_call_ctx;
extern void *tall_trans_ctx;
static int msc_mgw_setup(void)
{
struct mgcp_client *mgcp_client_single;
unsigned int pool_members_initalized;
/* Initialize MGW pool. This initalizes and connects all MGCP clients that are currently configured in
* the pool. Adding additional MGCP clients to the pool is possible but the user has to configure and
* (re)connect them manually from the VTY. */
pool_members_initalized = mgcp_client_pool_connect(msc_network->mgw.mgw_pool);
if (pool_members_initalized) {
LOGP(DMSC, LOGL_NOTICE,
"MGW pool with %u pool members configured, (ignoring MGW configuration in VTY node 'msc').\n",
pool_members_initalized);
return 0;
}
/* Initialize and connect a single MGCP client. This MGCP client will appear as the one and only pool
* member if there is no MGW pool configured. */
LOGP(DMSC, LOGL_NOTICE, "No MGW pool configured, using MGW configuration in VTY node 'msc'\n");
mgcp_client_single = mgcp_client_init(msc_network, &msc_network->mgw.conf);
if (!mgcp_client_single) {
LOGP(DMSC, LOGL_ERROR, "MGW (single) client initalization failed\n");
return -EINVAL;
}
if (mgcp_client_connect(mgcp_client_single)) {
LOGP(DMSC, LOGL_ERROR, "MGW (single) connect failed at (%s:%u)\n",
msc_network->mgw.conf.remote_addr,
msc_network->mgw.conf.remote_port);
return -EINVAL;
}
mgcp_client_pool_register_single(msc_network->mgw.mgw_pool, mgcp_client_single);
return 0;
}
int main(int argc, char **argv)
{
int rc;
@ -705,13 +741,8 @@ TODO: we probably want some of the _net_ ctrl commands from bsc_base_ctrl_cmds_i
if (sms_queue_start(msc_network) != 0)
return -1;
msc_network->mgw.client = mgcp_client_init(
msc_network, &msc_network->mgw.conf);
if (mgcp_client_connect(msc_network->mgw.client)) {
fprintf(stderr, "MGCPGW connect failed\n");
if (msc_mgw_setup() != 0)
return 7;
}
if (ss7_setup(tall_msc_ctx, &sccp_a, &sccp_iu)) {
fprintf(stderr, "Setting up SCCP client failed.\n");

View File

@ -1136,6 +1136,7 @@ static void run_tests(int nr)
struct gsm_network *test_net(void *ctx)
{
struct gsm_network *net = gsm_network_init(ctx, mncc_recv);
struct mgcp_client *client;
net->gsup_server_addr_str = talloc_strdup(net, "no_gsup_server");
net->gsup_server_port = 0;
@ -1172,8 +1173,9 @@ struct gsm_network *test_net(void *ctx)
net->mgw.tdefs = g_mgw_tdefs;
mgcp_client_conf_init(&net->mgw.conf);
net->mgw.tdefs = g_mgw_tdefs;
net->mgw.client = mgcp_client_init(net, &net->mgw.conf);
net->mgw.mgw_pool = mgcp_client_pool_alloc(net);
client = mgcp_client_init(net, &net->mgw.conf);
mgcp_client_pool_register_single(net->mgw.mgw_pool, client);
return net;
}

View File

@ -27,6 +27,8 @@ OsmoMSC(config-net)# list
no timezone
call-waiting
no call-waiting
mgw <0-255>
no mgw <0-255>
OsmoMSC(config-net)# encryption?
encryption Encryption options
@ -152,6 +154,10 @@ network
authentication optional
rrlp mode none
mm info 1
mgw 0
mgw local-port 2728
mgw remote-ip 127.0.0.1
mgw remote-port 2427
msc
mncc guard-timeout 180
ncss guard-timeout 30
@ -160,9 +166,6 @@ msc
...
auth-tuple-max-reuse-count 3
auth-tuple-reuse-on-error 1
mgw local-port 2728
mgw remote-ip 127.0.0.1
mgw remote-port 2427
mncc-int
default-codec tch-f fr
default-codec tch-h hr