From d7bf0dcae8f8e6b2ade7032057dfed5601a3cb4b Mon Sep 17 00:00:00 2001 From: Philipp Maier Date: Thu, 8 Jun 2017 14:18:47 +0200 Subject: mgcp: improve endpoint management Currently the assignment of endpoint identifiers works by just incrementing a counter. The mgcpgw only has a limited amount of endpoint identifiers avaliable, this means we will run out of endpoints after only a few calls. This commit adds a mechanism to keep track of used endpoint identifiers so unused endpoint identifiers can be re-used --- openbsc/include/openbsc/mgcpgw_client.h | 10 +++-- openbsc/src/libmgcp/mgcpgw_client.c | 72 ++++++++++++++++++++++++++++++--- openbsc/src/libmgcp/mgcpgw_client_vty.c | 30 ++++++++++++++ 3 files changed, 104 insertions(+), 8 deletions(-) diff --git a/openbsc/include/openbsc/mgcpgw_client.h b/openbsc/include/openbsc/mgcpgw_client.h index 8220cfa51..87fb27627 100644 --- a/openbsc/include/openbsc/mgcpgw_client.h +++ b/openbsc/include/openbsc/mgcpgw_client.h @@ -24,8 +24,8 @@ struct mgcpgw_client_conf { int local_port; const char *remote_addr; int remote_port; - unsigned int first_endpoint; - unsigned int last_endpoint; + uint16_t first_endpoint; + uint16_t last_endpoint; }; struct mgcp_response_head { @@ -63,7 +63,11 @@ const char *mgcpgw_client_remote_addr_str(struct mgcpgw_client *mgcp); uint16_t mgcpgw_client_remote_port(struct mgcpgw_client *mgcp); uint32_t mgcpgw_client_remote_addr_n(struct mgcpgw_client *mgcp); -unsigned int mgcpgw_client_next_endpoint(struct mgcpgw_client *client); +/* Find and seize an unsused endpoint id */ +int mgcpgw_client_next_endpoint(struct mgcpgw_client *client); + +/* Release a seized endpoint id to make it available again for other calls */ +void mgcpgw_client_release_endpoint(uint16_t id, struct mgcpgw_client *client); int mgcp_response_parse_params(struct mgcp_response *r); diff --git a/openbsc/src/libmgcp/mgcpgw_client.c b/openbsc/src/libmgcp/mgcpgw_client.c index 0c2106704..2cafcf2a0 100644 --- a/openbsc/src/libmgcp/mgcpgw_client.c +++ b/openbsc/src/libmgcp/mgcpgw_client.c @@ -40,8 +40,13 @@ struct mgcpgw_client { uint32_t remote_addr; struct osmo_wqueue wq; mgcp_trans_id_t next_trans_id; - uint16_t next_endpoint; struct llist_head responses_pending; + struct llist_head inuse_endpoints; +}; + +struct mgcp_inuse_endpoint { + struct llist_head entry; + uint16_t id; }; void mgcpgw_client_conf_init(struct mgcpgw_client_conf *conf) @@ -52,13 +57,67 @@ void mgcpgw_client_conf_init(struct mgcpgw_client_conf *conf) .local_port = -1, .remote_addr = NULL, .remote_port = -1, + .first_endpoint = 0, + .last_endpoint = 0, }; } -unsigned int mgcpgw_client_next_endpoint(struct mgcpgw_client *client) +/* Test if a given endpoint id is currently in use */ +static bool endpoint_in_use(uint16_t id, struct mgcpgw_client *client) { - /* FIXME: wrapping / cleanup + re-use */ - return client->next_endpoint ++; + struct mgcp_inuse_endpoint *endpoint; + llist_for_each_entry(endpoint, &client->inuse_endpoints, entry) { + if (endpoint->id == id) + return true; + } + + return false; +} + +/* Find and seize an unsused endpoint id */ +int mgcpgw_client_next_endpoint(struct mgcpgw_client *client) +{ + int i; + uint16_t first_endpoint = client->actual.first_endpoint; + uint16_t last_endpoint = client->actual.last_endpoint; + struct mgcp_inuse_endpoint *endpoint; + + /* Use the maximum permitted range if the VTY + * configuration does not specify a range */ + if (client->actual.last_endpoint == 0) { + first_endpoint = 1; + last_endpoint = 65534; + } + + /* Test the permitted endpoint range for an endpoint + * number that is not in use. When a suitable endpoint + * number can be found, seize it by adding it to the + * inuse list. */ + for (i=first_endpoint;iid = i; + llist_add_tail(&endpoint->entry, &client->inuse_endpoints); + return endpoint->id; + } + } + + /* All endpoints are busy! */ + return -EINVAL; +} + +/* Release a seized endpoint id to make it available again for other calls */ +void mgcpgw_client_release_endpoint(uint16_t id, struct mgcpgw_client *client) +{ + struct mgcp_inuse_endpoint *endpoint; + struct mgcp_inuse_endpoint *endpoint_tmp; + llist_for_each_entry_safe(endpoint, endpoint_tmp, &client->inuse_endpoints, entry) { + if (endpoint->id == id) { + llist_del(&endpoint->entry); + talloc_free(endpoint); + } + } } static void mgcpgw_client_handle_response(struct mgcpgw_client *mgcp, @@ -281,9 +340,9 @@ struct mgcpgw_client *mgcpgw_client_init(void *ctx, mgcp = talloc_zero(ctx, struct mgcpgw_client); INIT_LLIST_HEAD(&mgcp->responses_pending); + INIT_LLIST_HEAD(&mgcp->inuse_endpoints); mgcp->next_trans_id = 1; - mgcp->next_endpoint = 1; mgcp->actual.local_addr = conf->local_addr ? conf->local_addr : MGCPGW_CLIENT_LOCAL_ADDR_DEFAULT; @@ -295,6 +354,9 @@ struct mgcpgw_client *mgcpgw_client_init(void *ctx, mgcp->actual.remote_port = conf->remote_port >= 0 ? (uint16_t)conf->remote_port : MGCPGW_CLIENT_REMOTE_PORT_DEFAULT; + mgcp->actual.first_endpoint = conf->first_endpoint > 0 ? (uint16_t)conf->first_endpoint : 0; + mgcp->actual.last_endpoint = conf->last_endpoint > 0 ? (uint16_t)conf->last_endpoint : 0; + return mgcp; } diff --git a/openbsc/src/libmgcp/mgcpgw_client_vty.c b/openbsc/src/libmgcp/mgcpgw_client_vty.c index a42ee4e5d..8670192e9 100644 --- a/openbsc/src/libmgcp/mgcpgw_client_vty.c +++ b/openbsc/src/libmgcp/mgcpgw_client_vty.c @@ -79,10 +79,32 @@ DEFUN(cfg_mgcpgw_remote_port, cfg_mgcpgw_remote_port_cmd, return CMD_SUCCESS; } +DEFUN(cfg_mgcpgw_endpoint_range, cfg_mgcpgw_endpoint_range_cmd, + "mgcpgw endpoint-range <1-65534> <1-65534>", + MGCPGW_STR "usable range of endpoint identifiers\n" + "set first useable endpoint identifier\n" + "set the last useable endpoint identifier\n") +{ + uint16_t first_endpoint = atoi(argv[0]); + uint16_t last_endpoint = atoi(argv[1]); + + if (last_endpoint < first_endpoint) { + vty_out(vty, "last endpoint must be greater than first endpoint!%s", + VTY_NEWLINE); + return CMD_SUCCESS; + } + + global_mgcpgw_client_conf->first_endpoint = first_endpoint; + global_mgcpgw_client_conf->last_endpoint = last_endpoint; + return CMD_SUCCESS; +} + int mgcpgw_client_config_write(struct vty *vty, const char *indent) { const char *addr; int port; + uint16_t first_endpoint; + uint16_t last_endpoint; addr = global_mgcpgw_client_conf->local_addr; if (addr) @@ -102,6 +124,13 @@ int mgcpgw_client_config_write(struct vty *vty, const char *indent) vty_out(vty, "%smgcpgw remote-port %u%s", indent, (uint16_t)port, VTY_NEWLINE); + first_endpoint = global_mgcpgw_client_conf->first_endpoint; + last_endpoint = global_mgcpgw_client_conf->last_endpoint; + if (last_endpoint != 0) { + vty_out(vty, "%smgcpgw endpoint-range %u %u%s", indent, + first_endpoint, last_endpoint, VTY_NEWLINE); + } + return CMD_SUCCESS; } @@ -113,4 +142,5 @@ void mgcpgw_client_vty_init(int node, struct mgcpgw_client_conf *conf) install_element(node, &cfg_mgcpgw_local_port_cmd); install_element(node, &cfg_mgcpgw_remote_ip_cmd); install_element(node, &cfg_mgcpgw_remote_port_cmd); + install_element(node, &cfg_mgcpgw_endpoint_range_cmd); } -- cgit v1.2.3