Merge branch 'zecke/features/osmux-reliability'
Not verified that the audio handling is working. I saw a circuit set-up of the call though.
This commit is contained in:
commit
d74cce266b
|
@ -192,6 +192,8 @@ struct mgcp_endpoint {
|
|||
/* Osmux state: disabled, activating, active */
|
||||
enum osmux_state state;
|
||||
/* Allocated Osmux circuit ID for this endpoint */
|
||||
int allocated_cid;
|
||||
/* Used Osmux circuit ID for this endpoint */
|
||||
uint8_t cid;
|
||||
/* handle to batch messages */
|
||||
struct osmux_in_handle *in;
|
||||
|
|
|
@ -14,6 +14,8 @@ int osmux_init(int role, struct mgcp_config *cfg);
|
|||
int osmux_enable_endpoint(struct mgcp_endpoint *endp, int role,
|
||||
struct in_addr *addr, uint16_t port);
|
||||
void osmux_disable_endpoint(struct mgcp_endpoint *endp);
|
||||
void osmux_allocate_cid(struct mgcp_endpoint *endp);
|
||||
void osmux_release_cid(struct mgcp_endpoint *endp);
|
||||
|
||||
int osmux_xfrm_to_rtp(struct mgcp_endpoint *endp, int type, char *buf, int rc);
|
||||
int osmux_xfrm_to_osmux(int type, char *buf, int rc, struct mgcp_endpoint *endp);
|
||||
|
@ -22,6 +24,7 @@ int osmux_send_dummy(struct mgcp_endpoint *endp);
|
|||
|
||||
int osmux_get_cid(void);
|
||||
void osmux_put_cid(uint8_t osmux_cid);
|
||||
int osmux_used_cid(void);
|
||||
|
||||
enum osmux_state {
|
||||
OSMUX_STATE_DISABLED = 0,
|
||||
|
@ -29,4 +32,10 @@ enum osmux_state {
|
|||
OSMUX_STATE_ENABLED,
|
||||
};
|
||||
|
||||
enum osmux_usage {
|
||||
OSMUX_USAGE_OFF = 0,
|
||||
OSMUX_USAGE_ON = 1,
|
||||
OSMUX_USAGE_ONLY = 2,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -492,6 +492,19 @@ void osmux_disable_endpoint(struct mgcp_endpoint *endp)
|
|||
osmux_handle_put(endp->osmux.in);
|
||||
}
|
||||
|
||||
void osmux_release_cid(struct mgcp_endpoint *endp)
|
||||
{
|
||||
if (endp->osmux.allocated_cid >= 0)
|
||||
osmux_put_cid(endp->osmux.allocated_cid);
|
||||
endp->osmux.allocated_cid = -1;
|
||||
}
|
||||
|
||||
void osmux_allocate_cid(struct mgcp_endpoint *endp)
|
||||
{
|
||||
osmux_release_cid(endp);
|
||||
endp->osmux.allocated_cid = osmux_get_cid();
|
||||
}
|
||||
|
||||
/* We don't need to send the dummy load for osmux so often as another endpoint
|
||||
* may have already punched the hole in the firewall. This approach is simple
|
||||
* though.
|
||||
|
@ -532,11 +545,25 @@ int osmux_send_dummy(struct mgcp_endpoint *endp)
|
|||
/* bsc-nat allocates/releases the Osmux circuit ID */
|
||||
static uint8_t osmux_cid_bitmap[16];
|
||||
|
||||
int osmux_used_cid(void)
|
||||
{
|
||||
int i, j, used = 0;
|
||||
|
||||
for (i = 0; i < sizeof(osmux_cid_bitmap); i++) {
|
||||
for (j = 0; j < 8; j++) {
|
||||
if (osmux_cid_bitmap[i] & (1 << j))
|
||||
used += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return used;
|
||||
}
|
||||
|
||||
int osmux_get_cid(void)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < sizeof(osmux_cid_bitmap) / 8; i++) {
|
||||
for (i = 0; i < sizeof(osmux_cid_bitmap); i++) {
|
||||
for (j = 0; j < 8; j++) {
|
||||
if (osmux_cid_bitmap[i] & (1 << j))
|
||||
continue;
|
||||
|
|
|
@ -818,6 +818,10 @@ mgcp_header_done:
|
|||
if (osmux_cid >= 0) {
|
||||
endp->osmux.cid = osmux_cid;
|
||||
endp->osmux.state = OSMUX_STATE_ACTIVATING;
|
||||
} else if(endp->cfg->osmux == OSMUX_USAGE_ONLY) {
|
||||
LOGP(DMGCP, LOGL_ERROR,
|
||||
"Osmux only and no osmux offered on 0x%x\n", ENDPOINT_NUMBER(endp));
|
||||
goto error2;
|
||||
}
|
||||
|
||||
endp->allocated = 1;
|
||||
|
@ -1310,6 +1314,7 @@ int mgcp_endpoints_allocate(struct mgcp_trunk_config *tcfg)
|
|||
return -1;
|
||||
|
||||
for (i = 0; i < tcfg->number_endpoints; ++i) {
|
||||
tcfg->endpoints[i].osmux.allocated_cid = -1;
|
||||
tcfg->endpoints[i].ci = CI_UNUSED;
|
||||
tcfg->endpoints[i].cfg = tcfg->cfg;
|
||||
tcfg->endpoints[i].tcfg = tcfg;
|
||||
|
@ -1350,6 +1355,9 @@ void mgcp_release_endp(struct mgcp_endpoint *endp)
|
|||
if (endp->osmux.state == OSMUX_STATE_ENABLED)
|
||||
osmux_disable_endpoint(endp);
|
||||
|
||||
/* release the circuit ID if it had been allocated */
|
||||
osmux_release_cid(endp);
|
||||
|
||||
memset(&endp->taps, 0, sizeof(endp->taps));
|
||||
}
|
||||
|
||||
|
|
|
@ -139,8 +139,19 @@ static int config_write_mgcp(struct vty *vty)
|
|||
if (g_cfg->bts_force_ptime > 0)
|
||||
vty_out(vty, " rtp force-ptime %d%s", g_cfg->bts_force_ptime, VTY_NEWLINE);
|
||||
vty_out(vty, " transcoder-remote-base %u%s", g_cfg->transcoder_remote_base, VTY_NEWLINE);
|
||||
vty_out(vty, " osmux %s%s",
|
||||
g_cfg->osmux == 1 ? "on" : "off", VTY_NEWLINE);
|
||||
|
||||
switch (g_cfg->osmux) {
|
||||
case OSMUX_USAGE_ON:
|
||||
vty_out(vty, " osmux on%s", VTY_NEWLINE);
|
||||
break;
|
||||
case OSMUX_USAGE_ONLY:
|
||||
vty_out(vty, " osmux only%s", VTY_NEWLINE);
|
||||
break;
|
||||
case OSMUX_USAGE_OFF:
|
||||
default:
|
||||
vty_out(vty, " osmux off%s", VTY_NEWLINE);
|
||||
break;
|
||||
}
|
||||
if (g_cfg->osmux) {
|
||||
vty_out(vty, " osmux batch-factor %d%s",
|
||||
g_cfg->osmux_batch, VTY_NEWLINE);
|
||||
|
@ -226,6 +237,9 @@ DEFUN(show_mcgp, show_mgcp_cmd,
|
|||
llist_for_each_entry(trunk, &g_cfg->trunks, entry)
|
||||
dump_trunk(vty, trunk, show_stats);
|
||||
|
||||
if (g_cfg->osmux)
|
||||
vty_out(vty, "Osmux used CID: %d%s", osmux_used_cid(), VTY_NEWLINE);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1246,18 +1260,24 @@ DEFUN(reset_all_endp, reset_all_endp_cmd,
|
|||
#define OSMUX_STR "RTP multiplexing\n"
|
||||
DEFUN(cfg_mgcp_osmux,
|
||||
cfg_mgcp_osmux_cmd,
|
||||
"osmux (on|off)",
|
||||
OSMUX_STR "Enable OSMUX\n" "Disable OSMUX\n")
|
||||
"osmux (on|off|only)",
|
||||
OSMUX_STR "Enable OSMUX\n" "Disable OSMUX\n" "Only use OSMUX\n")
|
||||
{
|
||||
if (strcmp(argv[0], "on") == 0) {
|
||||
g_cfg->osmux = 1;
|
||||
if (g_cfg->trunk.audio_loop) {
|
||||
vty_out(vty, "Cannot use `loop' with `osmux'.%s",
|
||||
VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
} else if (strcmp(argv[0], "off") == 0)
|
||||
g_cfg->osmux = 0;
|
||||
if (strcmp(argv[0], "off") == 0) {
|
||||
g_cfg->osmux = OSMUX_USAGE_OFF;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
if (strcmp(argv[0], "on") == 0)
|
||||
g_cfg->osmux = OSMUX_USAGE_ON;
|
||||
else if (strcmp(argv[0], "only") == 0)
|
||||
g_cfg->osmux = OSMUX_USAGE_ONLY;
|
||||
|
||||
if (g_cfg->trunk.audio_loop) {
|
||||
vty_out(vty, "Cannot use `loop' with `osmux'.%s",
|
||||
VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -499,6 +499,15 @@ struct nat_sccp_connection *bsc_mgcp_find_con(struct bsc_nat *nat, int endpoint)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static int nat_osmux_only(struct mgcp_config *mgcp_cfg, struct bsc_config *bsc_cfg)
|
||||
{
|
||||
if (mgcp_cfg->osmux == OSMUX_USAGE_ONLY)
|
||||
return 1;
|
||||
if (bsc_cfg->osmux == OSMUX_USAGE_ONLY)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bsc_mgcp_policy_cb(struct mgcp_trunk_config *tcfg, int endpoint, int state, const char *transaction_id)
|
||||
{
|
||||
struct bsc_nat *nat;
|
||||
|
@ -506,7 +515,6 @@ static int bsc_mgcp_policy_cb(struct mgcp_trunk_config *tcfg, int endpoint, int
|
|||
struct nat_sccp_connection *sccp;
|
||||
struct mgcp_endpoint *mgcp_endp;
|
||||
struct msgb *bsc_msg;
|
||||
int osmux_cid = -1;
|
||||
|
||||
nat = tcfg->cfg->data;
|
||||
bsc_endp = &nat->bsc_endpoints[endpoint];
|
||||
|
@ -544,14 +552,23 @@ static int bsc_mgcp_policy_cb(struct mgcp_trunk_config *tcfg, int endpoint, int
|
|||
}
|
||||
|
||||
/* Allocate a Osmux circuit ID */
|
||||
if (state == MGCP_ENDP_CRCX &&
|
||||
nat->mgcp_cfg->osmux && sccp->bsc->cfg->osmux)
|
||||
osmux_cid = osmux_get_cid();
|
||||
if (state == MGCP_ENDP_CRCX) {
|
||||
if (nat->mgcp_cfg->osmux && sccp->bsc->cfg->osmux) {
|
||||
osmux_allocate_cid(mgcp_endp);
|
||||
if (mgcp_endp->osmux.allocated_cid < 0 &&
|
||||
nat_osmux_only(nat->mgcp_cfg, sccp->bsc->cfg)) {
|
||||
LOGP(DMGCP, LOGL_ERROR,
|
||||
"Rejecting usage of endpoint\n");
|
||||
return MGCP_POLICY_REJECT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* we need to generate a new and patched message */
|
||||
bsc_msg = bsc_mgcp_rewrite((char *) nat->mgcp_msg, nat->mgcp_length,
|
||||
sccp->bsc_endp, mgcp_bts_src_addr(mgcp_endp),
|
||||
mgcp_endp->bts_end.local_port, osmux_cid,
|
||||
mgcp_endp->bts_end.local_port,
|
||||
mgcp_endp->osmux.allocated_cid,
|
||||
&mgcp_endp->net_end.codec.payload_type,
|
||||
nat->sdp_ensure_amr_mode_set);
|
||||
if (!bsc_msg) {
|
||||
|
@ -571,10 +588,10 @@ static int bsc_mgcp_policy_cb(struct mgcp_trunk_config *tcfg, int endpoint, int
|
|||
/* Annotate the allocated Osmux CID until the bsc confirms that
|
||||
* it agrees to use Osmux for this voice flow.
|
||||
*/
|
||||
if (osmux_cid >= 0 &&
|
||||
if (mgcp_endp->osmux.allocated_cid >= 0 &&
|
||||
mgcp_endp->osmux.state != OSMUX_STATE_ENABLED) {
|
||||
mgcp_endp->osmux.state = OSMUX_STATE_ACTIVATING;
|
||||
mgcp_endp->osmux.cid = osmux_cid;
|
||||
mgcp_endp->osmux.cid = mgcp_endp->osmux.allocated_cid;
|
||||
}
|
||||
|
||||
socklen_t len = sizeof(sock);
|
||||
|
@ -596,7 +613,7 @@ static int bsc_mgcp_policy_cb(struct mgcp_trunk_config *tcfg, int endpoint, int
|
|||
|
||||
/* libmgcp clears the MGCP endpoint for us */
|
||||
if (mgcp_endp->osmux.state == OSMUX_STATE_ENABLED)
|
||||
osmux_put_cid(mgcp_endp->osmux.cid);
|
||||
osmux_release_cid(mgcp_endp);
|
||||
|
||||
return MGCP_POLICY_CONT;
|
||||
} else {
|
||||
|
@ -665,8 +682,7 @@ static void bsc_mgcp_osmux_confirm(struct mgcp_endpoint *endp, const char *str)
|
|||
osmux_cid);
|
||||
return;
|
||||
err:
|
||||
osmux_put_cid(endp->osmux.cid);
|
||||
endp->osmux.cid = -1;
|
||||
osmux_release_cid(endp);
|
||||
endp->osmux.state = OSMUX_STATE_DISABLED;
|
||||
}
|
||||
|
||||
|
@ -734,6 +750,16 @@ void bsc_mgcp_forward(struct bsc_connection *bsc, struct msgb *msg)
|
|||
if (endp->osmux.state == OSMUX_STATE_ACTIVATING)
|
||||
bsc_mgcp_osmux_confirm(endp, (const char *) msg->l2h);
|
||||
|
||||
/* If we require osmux and it is disabled.. fail */
|
||||
if (nat_osmux_only(bsc->nat->mgcp_cfg, bsc->cfg) &&
|
||||
endp->osmux.state == OSMUX_STATE_DISABLED) {
|
||||
LOGP(DMGCP, LOGL_ERROR,
|
||||
"Failed to activate osmux endpoint 0x%x\n",
|
||||
ENDPOINT_NUMBER(endp));
|
||||
free_chan_downstream(endp, bsc_endp, bsc);
|
||||
return;
|
||||
}
|
||||
|
||||
/* free some stuff */
|
||||
talloc_free(bsc_endp->transaction_id);
|
||||
bsc_endp->transaction_id = NULL;
|
||||
|
@ -792,7 +818,7 @@ static void patch_mgcp(struct msgb *output, const char *op, const char *tok,
|
|||
int slen;
|
||||
int ret;
|
||||
char buf[40];
|
||||
char osmux_extension[strlen("X-Osmux: 255")];
|
||||
char osmux_extension[strlen("\nX-Osmux: 255") + 1];
|
||||
|
||||
buf[0] = buf[39] = '\0';
|
||||
ret = sscanf(tok, "%*s %s", buf);
|
||||
|
@ -803,7 +829,7 @@ static void patch_mgcp(struct msgb *output, const char *op, const char *tok,
|
|||
}
|
||||
|
||||
if (osmux_cid >= 0)
|
||||
sprintf(osmux_extension, "\nX-Osmux: %u", osmux_cid);
|
||||
sprintf(osmux_extension, "\nX-Osmux: %u", osmux_cid & 0xff);
|
||||
else
|
||||
osmux_extension[0] = '\0';
|
||||
|
||||
|
|
|
@ -162,8 +162,14 @@ static void config_write_bsc_single(struct vty *vty, struct bsc_config *bsc)
|
|||
if (bsc->paging_group != -1)
|
||||
vty_out(vty, " paging group %d%s", bsc->paging_group, VTY_NEWLINE);
|
||||
vty_out(vty, " paging forbidden %d%s", bsc->forbid_paging, VTY_NEWLINE);
|
||||
if (bsc->osmux)
|
||||
switch (bsc->osmux) {
|
||||
case OSMUX_USAGE_ON:
|
||||
vty_out(vty, " osmux on%s", VTY_NEWLINE);
|
||||
break;
|
||||
case OSMUX_USAGE_ONLY:
|
||||
vty_out(vty, " osmux only%s", VTY_NEWLINE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int config_write_bsc(struct vty *vty)
|
||||
|
@ -1124,18 +1130,20 @@ DEFUN(show_ussd_connection,
|
|||
#define OSMUX_STR "RTP multiplexing\n"
|
||||
DEFUN(cfg_bsc_osmux,
|
||||
cfg_bsc_osmux_cmd,
|
||||
"osmux (on|off)",
|
||||
OSMUX_STR "Enable OSMUX\n" "Disable OSMUX\n")
|
||||
"osmux (on|off|only)",
|
||||
OSMUX_STR "Enable OSMUX\n" "Disable OSMUX\n" "Only OSMUX\n")
|
||||
{
|
||||
struct bsc_config *conf = vty->index;
|
||||
int old = conf->osmux;
|
||||
|
||||
if (strcmp(argv[0], "on") == 0)
|
||||
conf->osmux = 1;
|
||||
conf->osmux = OSMUX_USAGE_ON;
|
||||
else if (strcmp(argv[0], "off") == 0)
|
||||
conf->osmux = 0;
|
||||
conf->osmux = OSMUX_USAGE_OFF;
|
||||
else if (strcmp(argv[0], "only") == 0)
|
||||
conf->osmux = OSMUX_USAGE_ONLY;
|
||||
|
||||
if (old == 0 && conf->osmux == 1 && !conf->nat->mgcp_cfg->osmux_init) {
|
||||
if (old == 0 && conf->osmux > 0 && !conf->nat->mgcp_cfg->osmux_init) {
|
||||
LOGP(DMGCP, LOGL_NOTICE, "Setting up OSMUX socket\n");
|
||||
if (osmux_init(OSMUX_ROLE_BSC_NAT, conf->nat->mgcp_cfg) < 0) {
|
||||
LOGP(DMGCP, LOGL_ERROR, "Cannot init OSMUX\n");
|
||||
|
@ -1143,7 +1151,7 @@ DEFUN(cfg_bsc_osmux,
|
|||
VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
} else if (old == 1 && conf->osmux == 0) {
|
||||
} else if (old > 0 && conf->osmux == 0) {
|
||||
LOGP(DMGCP, LOGL_NOTICE, "Disabling OSMUX socket\n");
|
||||
/* Don't stop the socket, we may already have ongoing voice
|
||||
* flows already using Osmux. This just switch indicates that
|
||||
|
|
|
@ -1175,6 +1175,31 @@ static void test_no_name(void)
|
|||
talloc_free(cfg);
|
||||
}
|
||||
|
||||
static void test_osmux_cid(void)
|
||||
{
|
||||
int id, i;
|
||||
|
||||
OSMO_ASSERT(osmux_used_cid() == 0);
|
||||
id = osmux_get_cid();
|
||||
OSMO_ASSERT(id == 0);
|
||||
OSMO_ASSERT(osmux_used_cid() == 1);
|
||||
osmux_put_cid(id);
|
||||
OSMO_ASSERT(osmux_used_cid() == 0);
|
||||
|
||||
for (i = 0; i < 128; ++i) {
|
||||
id = osmux_get_cid();
|
||||
OSMO_ASSERT(id == i);
|
||||
OSMO_ASSERT(osmux_used_cid() == i + 1);
|
||||
}
|
||||
|
||||
id = osmux_get_cid();
|
||||
OSMO_ASSERT(id == -1);
|
||||
|
||||
for (i = 0; i < 256; ++i)
|
||||
osmux_put_cid(i);
|
||||
OSMO_ASSERT(osmux_used_cid() == 0);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
osmo_init_logging(&log_info);
|
||||
|
@ -1193,6 +1218,7 @@ int main(int argc, char **argv)
|
|||
test_multilple_codec();
|
||||
test_no_cycle();
|
||||
test_no_name();
|
||||
test_osmux_cid();
|
||||
|
||||
printf("Done\n");
|
||||
return EXIT_SUCCESS;
|
||||
|
|
Loading…
Reference in New Issue