From 6de9d0ba35f6fc9c483ef75426364580ad9fae01 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 30 Oct 2012 16:32:19 +0100 Subject: nat: Address the FIXME and send the MDCX down to the BSC --- openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc') diff --git a/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c b/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c index e5384d1a7..80a34d313 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c +++ b/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c @@ -257,7 +257,7 @@ static void bsc_mgcp_send_mdcx(struct bsc_connection *bsc, int port, struct mgcp return; } - #warning "The MDCX is not send to the BSC. It should" + bsc_write_mgcp(bsc, (uint8_t *) buf, len); } static void bsc_mgcp_send_dlcx(struct bsc_connection *bsc, int endpoint) -- cgit v1.2.3 From 77956aa034a7ac5ddfdf91c7341d3bf82cb07367 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 5 Nov 2012 13:52:53 +0100 Subject: nat: Move all methods sending a response to the callagent to a single place For testing it can be nice to handle MGCP messages through the IPA protocol. Prepare the code to send the messages through other means. --- openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c b/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c index 80a34d313..1436ebd35 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c +++ b/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c @@ -62,6 +62,14 @@ #include #include +static void mgcp_queue_for_call_agent(struct bsc_nat *nat, struct msgb *output) +{ + if (osmo_wqueue_enqueue(&nat->mgcp_cfg->gw_fd, output) != 0) { + LOGP(DMGCP, LOGL_ERROR, "Failed to queue MGCP msg.\n"); + msgb_free(output); + } +} + int bsc_mgcp_nr_multiplexes(int max_endpoints) { int div = max_endpoints / 32; @@ -502,10 +510,7 @@ void bsc_mgcp_forward(struct bsc_connection *bsc, struct msgb *msg) return; } - if (osmo_wqueue_enqueue(&bsc->nat->mgcp_cfg->gw_fd, output) != 0) { - LOGP(DMGCP, LOGL_ERROR, "Failed to queue MGCP msg.\n"); - msgb_free(output); - } + mgcp_queue_for_call_agent(bsc->nat, output); } int bsc_mgcp_parse_response(const char *str, int *code, char transaction[60]) @@ -680,12 +685,8 @@ static int mgcp_do_read(struct osmo_fd *fd) msgb_free(msg); /* we do have a direct answer... e.g. AUEP */ - if (resp) { - if (osmo_wqueue_enqueue(&nat->mgcp_cfg->gw_fd, resp) != 0) { - LOGP(DMGCP, LOGL_ERROR, "Failed to enqueue msg.\n"); - msgb_free(resp); - } - } + if (resp) + mgcp_queue_for_call_agent(nat, resp); return 0; } -- cgit v1.2.3 From c327187259d74cf260c977f165963778de4bedb1 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 5 Nov 2012 14:54:56 +0100 Subject: nat: Make it possible to send MGCP messages through the IPA multiplex Instead of handling MGCP through the UDP socket, read and write messages through the ipa connection to the MSC. --- openbsc/include/openbsc/bsc_nat.h | 4 ++ openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c | 82 +++++++++++++++++++++++++------ openbsc/src/osmo-bsc_nat/bsc_nat.c | 11 ++++- openbsc/src/osmo-bsc_nat/bsc_nat_vty.c | 17 +++++++ openbsc/tests/bsc-nat/bsc_nat_test.c | 6 +++ 5 files changed, 105 insertions(+), 15 deletions(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h index 1698fa47f..4baaa8280 100644 --- a/openbsc/include/openbsc/bsc_nat.h +++ b/openbsc/include/openbsc/bsc_nat.h @@ -270,6 +270,7 @@ struct bsc_nat { struct mgcp_config *mgcp_cfg; uint8_t mgcp_msg[4096]; int mgcp_length; + int mgcp_ipa; /* msc things */ struct llist_head dests; @@ -463,6 +464,9 @@ struct bsc_nat_barr_entry { int bsc_nat_barr_adapt(void *ctx, struct rb_root *rbtree, const struct osmo_config_list *); int bsc_nat_barr_find(struct rb_root *root, const char *imsi, int *cm, int *lu); +void bsc_nat_send_mgcp_to_msc(struct bsc_nat *bsc_nat, struct msgb *msg); +void bsc_nat_handle_mgcp(struct bsc_nat *bsc, struct msgb *msg); + struct ctrl_handle *bsc_nat_controlif_setup(struct bsc_nat *nat, int port); void bsc_nat_ctrl_del_pending(struct bsc_cmd_list *pending); int bsc_nat_handle_ctrlif_msg(struct bsc_connection *bsc, struct msgb *msg); diff --git a/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c b/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c index 1436ebd35..480a8f6d1 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c +++ b/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c @@ -62,7 +62,7 @@ #include #include -static void mgcp_queue_for_call_agent(struct bsc_nat *nat, struct msgb *output) +static void send_direct(struct bsc_nat *nat, struct msgb *output) { if (osmo_wqueue_enqueue(&nat->mgcp_cfg->gw_fd, output) != 0) { LOGP(DMGCP, LOGL_ERROR, "Failed to queue MGCP msg.\n"); @@ -70,6 +70,14 @@ static void mgcp_queue_for_call_agent(struct bsc_nat *nat, struct msgb *output) } } +static void mgcp_queue_for_call_agent(struct bsc_nat *nat, struct msgb *output) +{ + if (nat->mgcp_ipa) + bsc_nat_send_mgcp_to_msc(nat, output); + else + send_direct(nat, output); +} + int bsc_mgcp_nr_multiplexes(int max_endpoints) { int div = max_endpoints / 32; @@ -656,6 +664,38 @@ copy: return output; } +/* + * This comes from the MSC and we will now parse it. The caller needs + * to free the msgb. + */ +void bsc_nat_handle_mgcp(struct bsc_nat *nat, struct msgb *msg) +{ + struct msgb *resp; + + if (!nat->mgcp_ipa) { + LOGP(DMGCP, LOGL_ERROR, "MGCP message not allowed on IPA.\n"); + return; + } + + if (msgb_l2len(msg) > sizeof(nat->mgcp_msg) - 1) { + LOGP(DMGCP, LOGL_ERROR, "MGCP msg too big for handling.\n"); + return; + } + + memcpy(nat->mgcp_msg, msg->l2h, msgb_l2len(msg)); + nat->mgcp_length = msgb_l2len(msg); + nat->mgcp_msg[nat->mgcp_length] = '\0'; + + /* now handle the message */ + resp = mgcp_handle_message(nat->mgcp_cfg, msg); + + /* we do have a direct answer... e.g. AUEP */ + if (resp) + mgcp_queue_for_call_agent(nat, resp); + + return; +} + static int mgcp_do_read(struct osmo_fd *fd) { struct bsc_nat *nat; @@ -705,21 +745,10 @@ static int mgcp_do_write(struct osmo_fd *bfd, struct msgb *msg) return rc; } -int bsc_mgcp_nat_init(struct bsc_nat *nat) +static int init_mgcp_socket(struct bsc_nat *nat, struct mgcp_config *cfg) { - int on; struct sockaddr_in addr; - struct mgcp_config *cfg = nat->mgcp_cfg; - - if (!cfg->call_agent_addr) { - LOGP(DMGCP, LOGL_ERROR, "The BSC nat requires the call agent ip to be set.\n"); - return -1; - } - - if (cfg->bts_ip) { - LOGP(DMGCP, LOGL_ERROR, "Do not set the BTS ip for the nat.\n"); - return -1; - } + int on; cfg->gw_fd.bfd.fd = socket(AF_INET, SOCK_DGRAM, 0); if (cfg->gw_fd.bfd.fd < 0) { @@ -765,6 +794,31 @@ int bsc_mgcp_nat_init(struct bsc_nat *nat) return -1; } + return 0; +} + +int bsc_mgcp_nat_init(struct bsc_nat *nat) +{ + struct mgcp_config *cfg = nat->mgcp_cfg; + + if (!cfg->call_agent_addr) { + LOGP(DMGCP, LOGL_ERROR, "The BSC nat requires the call agent ip to be set.\n"); + return -1; + } + + if (cfg->bts_ip) { + LOGP(DMGCP, LOGL_ERROR, "Do not set the BTS ip for the nat.\n"); + return -1; + } + + /* initialize the MGCP socket */ + if (!nat->mgcp_ipa) { + int rc = init_mgcp_socket(nat, cfg); + if (rc != 0) + return rc; + } + + /* some more MGCP config handling */ cfg->data = nat; cfg->policy_cb = bsc_mgcp_policy_cb; diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat.c b/openbsc/src/osmo-bsc_nat/bsc_nat.c index 792d33c23..e70f54952 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat.c @@ -333,6 +333,12 @@ static void send_mgcp_reset(struct bsc_connection *bsc) bsc_write_mgcp(bsc, mgcp_reset, sizeof mgcp_reset - 1); } +void bsc_nat_send_mgcp_to_msc(struct bsc_nat *nat, struct msgb *msg) +{ + ipaccess_prepend_header(msg, IPAC_PROTO_MGCP_OLD); + queue_for_msc(nat->msc_con, msg); +} + /* * Below is the handling of messages coming * from the MSC and need to be forwarded to @@ -820,8 +826,11 @@ static int ipaccess_msc_read_cb(struct osmo_fd *bfd) initialize_msc_if_needed(msc_con); else if (msg->l2h[0] == IPAC_MSGT_ID_GET) send_id_get_response(msc_con); - } else if (hh->proto == IPAC_PROTO_SCCP) + } else if (hh->proto == IPAC_PROTO_SCCP) { forward_sccp_to_bts(msc_con, msg); + } else if (hh->proto == IPAC_PROTO_MGCP_OLD) { + bsc_nat_handle_mgcp(nat, msg); + } msgb_free(msg); return 0; diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c b/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c index 7bbc89059..32e5106ae 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c @@ -143,6 +143,8 @@ static int config_write_nat(struct vty *vty) write_acc_lst(vty, lst); llist_for_each_entry(pgroup, &_nat->paging_groups, entry) write_pgroup_lst(vty, pgroup); + if (_nat->mgcp_ipa) + vty_out(vty, " mgcp-through-msc-ipa%s", VTY_NEWLINE); return CMD_SUCCESS; } @@ -657,6 +659,20 @@ DEFUN(cfg_nat_ussd_local, return CMD_SUCCESS; } +DEFUN(cfg_nat_mgcp_ipa, + cfg_nat_mgcp_ipa_cmd, + "mgcp-through-msc-ipa", + "This needs to be set at start. Handle MGCP messages through " + "the IPA protocol and not through the UDP socket.\n") +{ + if (_nat->mgcp_cfg->data) + vty_out(vty, + "%%the setting will not be applied right now.%s", + VTY_NEWLINE); + _nat->mgcp_ipa = 1; + return CMD_SUCCESS; +} + /* per BSC configuration */ DEFUN(cfg_bsc, cfg_bsc_cmd, "bsc BSC_NR", "BSC configuration\n" "Identifier of the BSC\n") @@ -1086,6 +1102,7 @@ int bsc_nat_vty_init(struct bsc_nat *nat) install_element(NAT_NODE, &cfg_nat_ussd_query_cmd); install_element(NAT_NODE, &cfg_nat_ussd_token_cmd); install_element(NAT_NODE, &cfg_nat_ussd_local_cmd); + install_element(NAT_NODE, &cfg_nat_mgcp_ipa_cmd); /* access-list */ install_element(NAT_NODE, &cfg_lst_imsi_allow_cmd); diff --git a/openbsc/tests/bsc-nat/bsc_nat_test.c b/openbsc/tests/bsc-nat/bsc_nat_test.c index 66b4ff5a7..3b5c24e36 100644 --- a/openbsc/tests/bsc-nat/bsc_nat_test.c +++ b/openbsc/tests/bsc-nat/bsc_nat_test.c @@ -1242,3 +1242,9 @@ int main(int argc, char **argv) printf("Testing execution completed.\n"); return 0; } + +/* stub */ +void bsc_nat_send_mgcp_to_msc(struct bsc_nat *nat, struct msgb *msg) +{ + abort(); +} -- cgit v1.2.3 From 462b7d7158937b51fbb833ea3066e01fe8322f37 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 24 Oct 2012 21:53:40 +0200 Subject: nat: We want the remote to respond to our DLCX request We want to send a TRAP with the MGCP statistics from the NAT and the connected BSC. The BSC endpoint can be either released because of a DLCX from the MGCP CallAgent or the SCCP Connection release on the A-link. This is why we need to queue the statistics when the deleting the endpoint on the BSC. The processing is continued once the response arrives. This code assumes that the response of the DLCX will be sent by the remote side. The current amount of outstanding responses can be seen on the VTY. This assumption is based on the fact that the BSC has already responded to the CRCX and maybe to the MDCX. The MGCP RFC is bended to prefix the transaction identifier with "nat-" to easily detect the response and hand it to the handler. This will then parse the response and generate the TRAP. The current version is v1. We assume that the transaction space is big enough and we will not re-assign the transaction identifier too early. --- openbsc/include/openbsc/bsc_nat.h | 31 ++++++ openbsc/include/openbsc/mgcp.h | 1 + openbsc/src/libmgcp/mgcp_protocol.c | 30 +++++- openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c | 168 ++++++++++++++++++++++++++++-- openbsc/src/osmo-bsc_nat/bsc_nat_utils.c | 1 + openbsc/src/osmo-bsc_nat/bsc_nat_vty.c | 5 +- openbsc/tests/bsc-nat/Makefile.am | 1 + openbsc/tests/bsc-nat/bsc_nat_test.c | 1 + openbsc/tests/mgcp/mgcp_test.c | 25 +++++ openbsc/tests/mgcp/mgcp_test.ok | 3 + 10 files changed, 256 insertions(+), 10 deletions(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h index 4baaa8280..6860342a0 100644 --- a/openbsc/include/openbsc/bsc_nat.h +++ b/openbsc/include/openbsc/bsc_nat.h @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -111,6 +112,9 @@ struct bsc_connection { int number_multiplexes; int max_endpoints; int last_endpoint; + int next_transaction; + uint32_t pending_dlcx_count; + struct llist_head pending_dlcx; /* track the pending commands for this BSC */ struct llist_head cmd_pending; @@ -332,6 +336,33 @@ struct bsc_nat_ussd_con { struct osmo_timer_list auth_timeout; }; +struct bsc_nat_call_stats { + struct llist_head entry; + + struct sccp_source_reference remote_ref; + struct sccp_source_reference src_ref; /* as seen by the MSC */ + + /* mgcp options */ + uint32_t ci; + int bts_rtp_port; + int net_rtp_port; + struct in_addr bts_addr; + struct in_addr net_addr; + + + /* as witnessed by the NAT */ + uint32_t net_ps; + uint32_t net_os; + uint32_t bts_pr; + uint32_t bts_or; + uint32_t bts_expected; + uint32_t bts_jitter; + int bts_loss; + + uint32_t trans_id; + int msc_endpoint; +}; + struct bsc_nat_reject_cause { int lu_reject_cause; int cm_reject_cause; diff --git a/openbsc/include/openbsc/mgcp.h b/openbsc/include/openbsc/mgcp.h index 7a416ddd1..811dcfda7 100644 --- a/openbsc/include/openbsc/mgcp.h +++ b/openbsc/include/openbsc/mgcp.h @@ -172,6 +172,7 @@ int mgcp_endpoints_allocate(struct mgcp_trunk_config *cfg); void mgcp_free_endp(struct mgcp_endpoint *endp); int mgcp_reset_transcoder(struct mgcp_config *cfg); void mgcp_format_stats(struct mgcp_endpoint *endp, char *stats, size_t size); +int mgcp_parse_stats(struct msgb *msg, uint32_t *ps, uint32_t *os, uint32_t *pr, uint32_t *_or, int *loss, uint32_t *jitter); /* * format helper functions diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c index 6919a591d..dc5e0f992 100644 --- a/openbsc/src/libmgcp/mgcp_protocol.c +++ b/openbsc/src/libmgcp/mgcp_protocol.c @@ -1167,9 +1167,37 @@ void mgcp_format_stats(struct mgcp_endpoint *endp, char *msg, size_t size) &expected, &ploss); jitter = mgcp_state_calc_jitter(&endp->net_state); - snprintf(msg, size, "\r\nP: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%d", + snprintf(msg, size, "\r\nP: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u", endp->bts_end.packets, endp->bts_end.octets, endp->net_end.packets, endp->net_end.octets, ploss, jitter); msg[size - 1] = '\0'; } + +int mgcp_parse_stats(struct msgb *msg, uint32_t *ps, uint32_t *os, + uint32_t *pr, uint32_t *_or, int *loss, uint32_t *jitter) +{ + char *line, *save; + int rc; + + /* initialize with bad values */ + *ps = *os = *pr = *_or = *jitter = UINT_MAX; + *loss = INT_MAX; + + + line = strtok_r((char *) msg->l2h, "\r\n", &save); + if (!line) + return -1; + + /* this can only parse the message that is created above... */ + for_each_line(line, save) { + switch (line[0]) { + case 'P': + rc = sscanf(line, "P: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u", + ps, os, pr, _or, loss, jitter); + return rc == 6 ? 0 : -1; + } + } + + return -1; +} diff --git a/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c b/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c index 480a8f6d1..a29e9d70d 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c +++ b/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c @@ -49,6 +49,7 @@ #include #include #include +#include #include @@ -276,14 +277,20 @@ static void bsc_mgcp_send_mdcx(struct bsc_connection *bsc, int port, struct mgcp bsc_write_mgcp(bsc, (uint8_t *) buf, len); } -static void bsc_mgcp_send_dlcx(struct bsc_connection *bsc, int endpoint) +static void bsc_mgcp_send_dlcx(struct bsc_connection *bsc, int endpoint, int trans) { char buf[2096]; int len; + /* + * The following is a bit of a spec violation. According to the + * MGCP grammar the transaction id is are upto 9 digits but we + * prefix it with an alpha numeric value so we can easily recognize + * it as a response. + */ len = snprintf(buf, sizeof(buf), - "DLCX 26 %x@mgw MGCP 1.0\r\n" - "Z: noanswer\r\n", endpoint); + "DLCX nat-%u %x@mgw MGCP 1.0\r\n", + trans, endpoint); if (len < 0) { LOGP(DMGCP, LOGL_ERROR, "snprintf for DLCX failed.\n"); return; @@ -298,18 +305,153 @@ void bsc_mgcp_init(struct sccp_connections *con) con->bsc_endp = -1; } +/** + * This code will remember the network side of the audio statistics and + * once the internal DLCX response arrives this can be combined with the + * the BSC side and forwarded as a trap. + */ +static void remember_pending_dlcx(struct sccp_connections *con, uint32_t transaction) +{ + struct bsc_nat_call_stats *stats; + struct bsc_connection *bsc = con->bsc; + struct mgcp_endpoint *endp; + + stats = talloc_zero(bsc, struct bsc_nat_call_stats); + if (!stats) { + LOGP(DNAT, LOGL_NOTICE, + "Failed to allocate statistics for endpoint 0x%x\n", + con->msc_endp); + return; + } + + /* take the endpoint here */ + endp = &bsc->nat->mgcp_cfg->trunk.endpoints[con->msc_endp]; + + stats->remote_ref = con->remote_ref; + stats->src_ref = con->patched_ref; + + stats->ci = endp->ci; + stats->bts_rtp_port = endp->bts_end.rtp_port; + stats->bts_addr = endp->bts_end.addr; + stats->net_rtp_port = endp->net_end.rtp_port; + stats->net_addr = endp->net_end.addr; + + stats->net_ps = endp->net_end.packets; + stats->net_os = endp->net_end.octets; + stats->bts_pr = endp->bts_end.packets; + stats->bts_or = endp->bts_end.octets; + mgcp_state_calc_loss(&endp->bts_state, &endp->bts_end, + &stats->bts_expected, &stats->bts_loss); + stats->bts_jitter = mgcp_state_calc_jitter(&endp->bts_state); + + stats->trans_id = transaction; + stats->msc_endpoint = con->msc_endp; + + bsc->pending_dlcx_count += 1; + llist_add_tail(&stats->entry, &bsc->pending_dlcx); +} + void bsc_mgcp_dlcx(struct sccp_connections *con) { /* send a DLCX down the stream */ if (con->bsc_endp != -1 && con->bsc->_endpoint_status) { + LOGP(DNAT, LOGL_NOTICE, + "Endpoint 0x%x was still allocated on bsc: %d. Freeing it.\n", + con->bsc_endp, con->bsc->cfg->nr); if (con->bsc->_endpoint_status[con->bsc_endp] != 1) LOGP(DNAT, LOGL_ERROR, "Endpoint 0x%x was not in use\n", con->bsc_endp); + remember_pending_dlcx(con, con->bsc->next_transaction); con->bsc->_endpoint_status[con->bsc_endp] = 0; - bsc_mgcp_send_dlcx(con->bsc, con->bsc_endp); + bsc_mgcp_send_dlcx(con->bsc, con->bsc_endp, con->bsc->next_transaction++); bsc_mgcp_free_endpoint(con->bsc->nat, con->msc_endp); } bsc_mgcp_init(con); + +} + +/* + * Search for the pending request + */ +static void handle_dlcx_response(struct bsc_connection *bsc, struct msgb *msg, + int code, const char *transaction) +{ + uint32_t trans_id = UINT32_MAX; + uint32_t b_ps, b_os, n_pr, n_or, jitter; + int loss; + struct bsc_nat_call_stats *tmp, *stat = NULL; + struct ctrl_cmd *cmd; + + /* parse the transaction identifier */ + int rc = sscanf(transaction, "nat-%u", &trans_id); + if (rc != 1) { + LOGP(DNAT, LOGL_ERROR, "Can not parse transaction id: '%s'\n", + transaction); + return; + } + + /* find the answer for the request we made */ + llist_for_each_entry(tmp, &bsc->pending_dlcx, entry) { + if (trans_id != tmp->trans_id) + continue; + + stat = tmp; + break; + } + + if (!stat) { + LOGP(DNAT, LOGL_ERROR, + "Can not find transaction for: %u\n", trans_id); + return; + } + + /* attempt to parse the data now */ + rc = mgcp_parse_stats(msg, &b_ps, &b_os, &n_pr, &n_or, &loss, &jitter); + if (rc != 0) + LOGP(DNAT, LOGL_ERROR, + "Can not parse connection statistics: %d\n", rc); + + /* send a trap now */ + cmd = ctrl_cmd_create(bsc, CTRL_TYPE_TRAP); + if (!cmd) { + LOGP(DNAT, LOGL_ERROR, + "Creating a ctrl cmd failed.\n"); + goto free_stat; + } + + cmd->id = "0"; + cmd->variable = "nat.call_stats.v1"; + cmd->reply = talloc_asprintf(cmd, + "bsc_id=%d,mg_ip_addr=%s,mg_port=%d,", + bsc->cfg->nr, inet_ntoa(stat->net_addr), + stat->net_rtp_port); + cmd->reply = talloc_asprintf_append(cmd->reply, + "endpoint_ip_addr=%s,endpoint_port=%d,", + inet_ntoa(stat->bts_addr), + stat->bts_rtp_port); + cmd->reply = talloc_asprintf_append(cmd->reply, + "nat_pkt_in=%u,nat_pkt_out=%u," + "nat_bytes_in=%u,nat_bytes_out=%u," + "nat_jitter=%u,nat_pkt_lost=%d,", + stat->bts_pr, stat->net_ps, + stat->bts_or, stat->net_os, + stat->bts_jitter, stat->bts_loss); + cmd->reply = talloc_asprintf_append(cmd->reply, + "bsc_pkt_in=%u,bsc_pkt_out=%u," + "bsc_bytes_in=%u,bsc_bytes_out=%u," + "bsc_jitter=%u,bsc_pkt_lost=%d", + n_pr, b_ps, + n_or, b_os, + jitter, loss); + + /* send it and be done */ + ctrl_cmd_send_to_all(bsc->nat->ctrl, cmd); + talloc_free(cmd); + +free_stat: + bsc->pending_dlcx_count -= 1; + llist_del(&stat->entry); + talloc_free(stat); } @@ -330,7 +472,8 @@ struct sccp_connections *bsc_mgcp_find_con(struct bsc_nat *nat, int endpoint) if (con) return con; - LOGP(DMGCP, LOGL_ERROR, "Failed to find the connection.\n"); + LOGP(DMGCP, LOGL_ERROR, + "Failed to find the connection for endpoint: 0x%x\n", endpoint); return NULL; } @@ -435,7 +578,7 @@ static void free_chan_downstream(struct mgcp_endpoint *endp, struct bsc_endpoint ENDPOINT_NUMBER(endp)); } else { if (con->bsc == bsc) { - bsc_mgcp_send_dlcx(bsc, con->bsc_endp); + bsc_mgcp_send_dlcx(bsc, con->bsc_endp, con->bsc->next_transaction++); } else { LOGP(DMGCP, LOGL_ERROR, "Endpoint belongs to a different BSC\n"); @@ -452,6 +595,9 @@ static void free_chan_downstream(struct mgcp_endpoint *endp, struct bsc_endpoint * this transaction and if it belongs to the BSC. Then we will * need to patch the content to point to the local network and we * need to update the I: that was assigned by the BSS. + * + * Only responses to CRCX and DLCX should arrive here. The DLCX + * needs to be handled specially to combine the two statistics. */ void bsc_mgcp_forward(struct bsc_connection *bsc, struct msgb *msg) { @@ -488,6 +634,11 @@ void bsc_mgcp_forward(struct bsc_connection *bsc, struct msgb *msg) break; } + if (!bsc_endp && strncmp("nat-", transaction_id, 4) == 0) { + handle_dlcx_response(bsc, msg, code, transaction_id); + return; + } + if (!bsc_endp) { LOGP(DMGCP, LOGL_ERROR, "Could not find active endpoint: %s for msg: '%s'\n", transaction_id, (const char *) msg->l2h); @@ -523,8 +674,11 @@ void bsc_mgcp_forward(struct bsc_connection *bsc, struct msgb *msg) int bsc_mgcp_parse_response(const char *str, int *code, char transaction[60]) { + int rc; /* we want to parse two strings */ - return sscanf(str, "%3d %59s\n", code, transaction) != 2; + rc = sscanf(str, "%3d %59s\n", code, transaction) != 2; + transaction[59] = '\0'; + return rc; } uint32_t bsc_mgcp_extract_ci(const char *str) diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c b/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c index 0c56a8cd9..2e6d9a363 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c @@ -132,6 +132,7 @@ struct bsc_connection *bsc_connection_alloc(struct bsc_nat *nat) con->nat = nat; osmo_wqueue_init(&con->write_queue, 100); INIT_LLIST_HEAD(&con->cmd_pending); + INIT_LLIST_HEAD(&con->pending_dlcx); return con; } diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c b/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c index 32e5106ae..e5993b4a8 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c @@ -206,10 +206,11 @@ DEFUN(show_bsc, show_bsc_cmd, "show bsc connections", llist_for_each_entry(con, &_nat->bsc_connections, list_entry) { getpeername(con->write_queue.bfd.fd, (struct sockaddr *) &sock, &len); - vty_out(vty, "BSC nr: %d auth: %d fd: %d peername: %s%s", + vty_out(vty, "BSC nr: %d auth: %d fd: %d peername: %s pending-stats: %u%s", con->cfg ? con->cfg->nr : -1, con->authenticated, con->write_queue.bfd.fd, - inet_ntoa(sock.sin_addr), VTY_NEWLINE); + inet_ntoa(sock.sin_addr), con->pending_dlcx_count, + VTY_NEWLINE); } return CMD_SUCCESS; diff --git a/openbsc/tests/bsc-nat/Makefile.am b/openbsc/tests/bsc-nat/Makefile.am index e284851a1..9b71d095c 100644 --- a/openbsc/tests/bsc-nat/Makefile.am +++ b/openbsc/tests/bsc-nat/Makefile.am @@ -14,6 +14,7 @@ bsc_nat_test_SOURCES = bsc_nat_test.c \ $(top_srcdir)/src/osmo-bsc_nat/bsc_nat_rewrite.c \ $(top_srcdir)/src/osmo-bsc_nat/bsc_mgcp_utils.c bsc_nat_test_LDADD = $(top_builddir)/src/libbsc/libbsc.a \ + $(top_srcdir)/src/libctrl/libctrl.a \ $(top_srcdir)/src/libmgcp/libmgcp.a \ $(top_srcdir)/src/libtrau/libtrau.a \ $(top_srcdir)/src/libcommon/libcommon.a \ diff --git a/openbsc/tests/bsc-nat/bsc_nat_test.c b/openbsc/tests/bsc-nat/bsc_nat_test.c index 3b5c24e36..c2931f98b 100644 --- a/openbsc/tests/bsc-nat/bsc_nat_test.c +++ b/openbsc/tests/bsc-nat/bsc_nat_test.c @@ -514,6 +514,7 @@ static void test_mgcp_ass_tracking(void) 33); nat->mgcp_cfg = mgcp_config_alloc(); nat->mgcp_cfg->trunk.number_endpoints = 64; + mgcp_endpoints_allocate(&nat->mgcp_cfg->trunk); bsc = bsc_connection_alloc(nat); bsc->cfg = bsc_config_alloc(nat, "foo"); diff --git a/openbsc/tests/mgcp/mgcp_test.c b/openbsc/tests/mgcp/mgcp_test.c index 4dfd2abe3..5565e7316 100644 --- a/openbsc/tests/mgcp/mgcp_test.c +++ b/openbsc/tests/mgcp/mgcp_test.c @@ -323,6 +323,30 @@ static void test_packet_loss_calc(void) } } +static void test_mgcp_stats(void) +{ + printf("Testing stat parsing\n"); + + uint32_t bps, bos, pr, _or, jitter; + struct msgb *msg; + int loss; + int rc; + + msg = create_msg(DLCX_RET); + rc = mgcp_parse_stats(msg, &bps, &bos, &pr, &_or, &loss, &jitter); + printf("Parsing result: %d\n", rc); + if (bps != 0 || bos != 0 || pr != 0 || _or != 0 || loss != 0 || jitter != 0) + printf("FAIL: Parsing failed1.\n"); + msgb_free(msg); + + msg = create_msg("250 7 OK\r\nP: PS=10, OS=20, PR=30, OR=40, PL=-3, JI=40\r\n"); + rc = mgcp_parse_stats(msg, &bps, &bos, &pr, &_or, &loss, &jitter); + printf("Parsing result: %d\n", rc); + if (bps != 10 || bos != 20 || pr != 30 || _or != 40 || loss != -3 || jitter != 40) + printf("FAIL: Parsing failed2.\n"); + msgb_free(msg); +} + int main(int argc, char **argv) { osmo_init_logging(&log_info); @@ -331,6 +355,7 @@ int main(int argc, char **argv) test_retransmission(); test_packet_loss_calc(); test_rqnt_cb(); + test_mgcp_stats(); printf("Done\n"); return EXIT_SUCCESS; diff --git a/openbsc/tests/mgcp/mgcp_test.ok b/openbsc/tests/mgcp/mgcp_test.ok index 224bba8d7..8711e38f2 100644 --- a/openbsc/tests/mgcp/mgcp_test.ok +++ b/openbsc/tests/mgcp/mgcp_test.ok @@ -25,4 +25,7 @@ Re-transmitting MDCX3 Testing DLCX Re-transmitting DLCX Testing packet loss calculation. +Testing stat parsing +Parsing result: 0 +Parsing result: 0 Done -- cgit v1.2.3 From 931ad6ac33d8efaf7f32f49c253c0cc7bbf595fc Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 12 Nov 2012 18:00:25 +0100 Subject: nat: Reword the log messages as this is normal operation The bsc_mgcp_dlcx method is called from the mgcp policy callback but also from inside the nat core when the SCCP connection is going away. --- openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc') diff --git a/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c b/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c index a29e9d70d..ba15618ec 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c +++ b/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c @@ -356,7 +356,7 @@ void bsc_mgcp_dlcx(struct sccp_connections *con) /* send a DLCX down the stream */ if (con->bsc_endp != -1 && con->bsc->_endpoint_status) { LOGP(DNAT, LOGL_NOTICE, - "Endpoint 0x%x was still allocated on bsc: %d. Freeing it.\n", + "Endpoint 0x%x was allocated for bsc: %d. Freeing it.\n", con->bsc_endp, con->bsc->cfg->nr); if (con->bsc->_endpoint_status[con->bsc_endp] != 1) LOGP(DNAT, LOGL_ERROR, "Endpoint 0x%x was not in use\n", con->bsc_endp); -- cgit v1.2.3 From 7c831ecd191bab20ab5330d16da147e9a12bbba8 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 12 Nov 2012 18:36:00 +0100 Subject: nat: Do not allow the amount of pending responses to grow infinitely Limit the amount of pending DLCX responses to three times the amount of available endpoints. Currently all MGCP messages are sent and handled in sequence. --- openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'openbsc') diff --git a/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c b/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c index ba15618ec..411d500d9 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c +++ b/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c @@ -347,6 +347,21 @@ static void remember_pending_dlcx(struct sccp_connections *con, uint32_t transac stats->trans_id = transaction; stats->msc_endpoint = con->msc_endp; + /* + * Too many pending requests.. let's remove the first two items. + */ + if (!llist_empty(&bsc->pending_dlcx) && + bsc->pending_dlcx_count >= bsc->cfg->max_endpoints * 3) { + struct bsc_nat_call_stats *tmp; + LOGP(DNAT, LOGL_ERROR, + "Too many(%d) pending DLCX responses on BSC: %d\n", + bsc->pending_dlcx_count, bsc->cfg->nr); + bsc->pending_dlcx_count -= 1; + tmp = (struct bsc_nat_call_stats *) bsc->pending_dlcx.next; + llist_del(&tmp->entry); + talloc_free(tmp); + } + bsc->pending_dlcx_count += 1; llist_add_tail(&stats->entry, &bsc->pending_dlcx); } -- cgit v1.2.3 From 7d7054eafa76f1b9cda588c6a46229f732b7ccad Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 12 Nov 2012 19:05:16 +0100 Subject: nat: Include the sccp_src_ref and sccp_dst_ref for this call This can help with some post analysis for failed calls and helps finding the connection in the pcap trace. --- openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c b/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c index 411d500d9..226486c32 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c +++ b/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c @@ -435,7 +435,7 @@ static void handle_dlcx_response(struct bsc_connection *bsc, struct msgb *msg, } cmd->id = "0"; - cmd->variable = "nat.call_stats.v1"; + cmd->variable = "nat.call_stats.v2"; cmd->reply = talloc_asprintf(cmd, "bsc_id=%d,mg_ip_addr=%s,mg_port=%d,", bsc->cfg->nr, inet_ntoa(stat->net_addr), @@ -454,10 +454,14 @@ static void handle_dlcx_response(struct bsc_connection *bsc, struct msgb *msg, cmd->reply = talloc_asprintf_append(cmd->reply, "bsc_pkt_in=%u,bsc_pkt_out=%u," "bsc_bytes_in=%u,bsc_bytes_out=%u," - "bsc_jitter=%u,bsc_pkt_lost=%d", + "bsc_jitter=%u,bsc_pkt_lost=%d,", n_pr, b_ps, n_or, b_os, jitter, loss); + cmd->reply = talloc_asprintf_append(cmd->reply, + "sccp_src_ref=%u,sccp_dst_ref=%u", + sccp_src_ref_to_int(&stat->src_ref), + sccp_src_ref_to_int(&stat->remote_ref)); /* send it and be done */ ctrl_cmd_send_to_all(bsc->nat->ctrl, cmd); -- cgit v1.2.3 From ac04d8d55e413d49ef0a9179bccf1147e6f2a87a Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 13 Nov 2012 21:54:36 +0100 Subject: nat: Name the variable more properly and begin with net.1.bsc.%d We can identify the NAT and BSC given the types of the variable, no need to put them into the value itself. --- openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c b/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c index 226486c32..85f940b49 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c +++ b/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c @@ -435,10 +435,11 @@ static void handle_dlcx_response(struct bsc_connection *bsc, struct msgb *msg, } cmd->id = "0"; - cmd->variable = "nat.call_stats.v2"; + cmd->variable = talloc_asprintf(cmd, "net.0.bsc.%d.call_stats.v2", + bsc->cfg->nr); cmd->reply = talloc_asprintf(cmd, - "bsc_id=%d,mg_ip_addr=%s,mg_port=%d,", - bsc->cfg->nr, inet_ntoa(stat->net_addr), + "mg_ip_addr=%s,mg_port=%d,", + inet_ntoa(stat->net_addr), stat->net_rtp_port); cmd->reply = talloc_asprintf_append(cmd->reply, "endpoint_ip_addr=%s,endpoint_port=%d,", -- cgit v1.2.3