<p>dexter has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-mgw/+/25008">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">mgcp_client: allow to reset endpoints on startup<br><br>Depending on the usecase of osmo_mpcg_client it may be helpful to send a<br>DLCX to certain endpoints. Usually this would be a wildcarded endpoint<br>that resets the entire trunk to drop lingering RTP flows which may still<br>present after a restart/crash, but it might be also a group of specific<br>endpoints. The user may specify an arbitrary amount of endpoints where<br>the mgcp client will send a DLCX to. It does not matter if the endpoints<br>are wildcarded or not.<br><br>Change-Id: I47e7ff858d5067b46d52329be5f362ff61c0dff8<br>Related: SYS#5535<br>---<br>M include/osmocom/mgcp_client/mgcp_client.h<br>M src/libosmo-mgcp-client/mgcp_client.c<br>M src/libosmo-mgcp-client/mgcp_client_vty.c<br>3 files changed, 131 insertions(+), 19 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-mgw refs/changes/08/25008/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmocom/mgcp_client/mgcp_client.h b/include/osmocom/mgcp_client/mgcp_client.h</span><br><span>index 02996a7..95c25b1 100644</span><br><span>--- a/include/osmocom/mgcp_client/mgcp_client.h</span><br><span>+++ b/include/osmocom/mgcp_client/mgcp_client.h</span><br><span>@@ -17,6 +17,12 @@</span><br><span> struct vty;</span><br><span> struct mgcp_client;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* Struct that holds one endpoint name */</span><br><span style="color: hsl(120, 100%, 40%);">+struct reset_ep {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct llist_head list;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *name;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct mgcp_client_conf {</span><br><span> const char *local_addr;</span><br><span> int local_port;</span><br><span>@@ -26,6 +32,12 @@</span><br><span> /* By default, we are always addressing the MGW with e.g. 'rtpbridge/123@mgw'.</span><br><span> * If this is nonempty, the contained name will be used instead of 'mgw'. */</span><br><span> char endpoint_domain_name[MGCP_ENDPOINT_MAXLEN];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* The user may configure certain endpoint names that are reset via DLCX</span><br><span style="color: hsl(120, 100%, 40%);">+ * on startup. Usually this will be one wildcarded endpoint e.g.</span><br><span style="color: hsl(120, 100%, 40%);">+ * 'rtpbridge/(wildcard)' or a number of specific E1 like e.g.</span><br><span style="color: hsl(120, 100%, 40%);">+ * 'ds/e1-0/s-3/su16-4' */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct llist_head reset_epnames;</span><br><span> };</span><br><span> </span><br><span> typedef unsigned int mgcp_trans_id_t;</span><br><span>diff --git a/src/libosmo-mgcp-client/mgcp_client.c b/src/libosmo-mgcp-client/mgcp_client.c</span><br><span>index 9d60ee8..3320ad7 100644</span><br><span>--- a/src/libosmo-mgcp-client/mgcp_client.c</span><br><span>+++ b/src/libosmo-mgcp-client/mgcp_client.c</span><br><span>@@ -201,6 +201,8 @@</span><br><span> .remote_addr = NULL,</span><br><span> .remote_port = -1,</span><br><span> };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ INIT_LLIST_HEAD(&conf->reset_epnames);</span><br><span> }</span><br><span> </span><br><span> static void mgcp_client_handle_response(struct mgcp_client *mgcp,</span><br><span>@@ -754,6 +756,8 @@</span><br><span> struct mgcp_client_conf *conf)</span><br><span> {</span><br><span> struct mgcp_client *mgcp;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct reset_ep *reset_ep;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct reset_ep *actual_reset_ep;</span><br><span> </span><br><span> mgcp = talloc_zero(ctx, struct mgcp_client);</span><br><span> if (!mgcp)</span><br><span>@@ -784,6 +788,12 @@</span><br><span> }</span><br><span> LOGP(DLMGCP, LOGL_NOTICE, "MGCP client: using endpoint domain '@%s'\n", mgcp_client_endpoint_domain(mgcp));</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ INIT_LLIST_HEAD(&mgcp->actual.reset_epnames);</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(reset_ep, &conf->reset_epnames, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ actual_reset_ep = talloc_memdup (ctx, reset_ep, sizeof(*reset_ep));</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_add_tail(&actual_reset_ep->list, &mgcp->actual.reset_epnames);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> return mgcp;</span><br><span> }</span><br><span> </span><br><span>@@ -823,6 +833,42 @@</span><br><span> return -EINVAL;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static const char *_mgcp_client_name_append_domain(const struct mgcp_client *mgcp, char *name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ static char endpoint[MGCP_ENDPOINT_MAXLEN];</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = snprintf(endpoint, sizeof(endpoint), "%s@%s", name, mgcp_client_endpoint_domain(mgcp));</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc > sizeof(endpoint) - 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DLMGCP, LOGL_ERROR, "MGCP endpoint exceeds maximum length of %zu: '%s@%s'\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ sizeof(endpoint) - 1, name, mgcp_client_endpoint_domain(mgcp));</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DLMGCP, LOGL_ERROR, "Cannot compose MGCP endpoint name\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ return endpoint;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Safely ignore the MGCP response to the DLCX sent via _mgcp_client_send_dlcx() */</span><br><span style="color: hsl(120, 100%, 40%);">+void _ignore_mgcp_response(struct mgcp_response *response, void *priv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Fromat DLCX message (fire and forget) and send it off to the MGW */</span><br><span style="color: hsl(120, 100%, 40%);">+static void _mgcp_client_send_dlcx(struct mgcp_client *mgcp, const char *epname) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *msgb_dlcx;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct mgcp_msg mgcp_msg_dlcx = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .verb = MGCP_VERB_DLCX,</span><br><span style="color: hsl(120, 100%, 40%);">+ .presence = MGCP_MSG_PRESENCE_ENDPOINT,</span><br><span style="color: hsl(120, 100%, 40%);">+ };</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_strlcpy(mgcp_msg_dlcx.endpoint, epname, sizeof(mgcp_msg_dlcx.endpoint));</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_dlcx = mgcp_msg_gen(mgcp, &mgcp_msg_dlcx);</span><br><span style="color: hsl(120, 100%, 40%);">+ mgcp_client_tx(mgcp, msgb_dlcx, &_ignore_mgcp_response, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! Initalize client connection (opens socket only, no request is sent yet)</span><br><span> * \param[in,out] mgcp MGCP client descriptor.</span><br><span> * \returns 0 on success, -EINVAL on error. */</span><br><span>@@ -830,6 +876,7 @@</span><br><span> {</span><br><span> struct osmo_wqueue *wq;</span><br><span> int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct reset_ep *reset_ep;</span><br><span> </span><br><span> if (!mgcp) {</span><br><span> LOGP(DLMGCP, LOGL_FATAL, "MGCPGW client not initialized properly\n");</span><br><span>@@ -852,9 +899,14 @@</span><br><span> goto error_close_fd;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> LOGP(DLMGCP, LOGL_INFO, "MGCP GW connection: %s\n", osmo_sock_get_name2(wq->bfd.fd));</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* If configured, send a DLCX message to the endpoints that are configured to</span><br><span style="color: hsl(120, 100%, 40%);">+ * be reset on startup. Usually this is a wildcarded endpoint. */</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(reset_ep, &mgcp->actual.reset_epnames, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DLMGCP, LOGL_INFO, "MGCP GW sending DLCX to: %s\n", _mgcp_client_name_append_domain(mgcp, reset_ep->name));</span><br><span style="color: hsl(120, 100%, 40%);">+ _mgcp_client_send_dlcx(mgcp, _mgcp_client_name_append_domain(mgcp, reset_ep->name));</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> return 0;</span><br><span> error_close_fd:</span><br><span> close(wq->bfd.fd);</span><br><span>@@ -894,24 +946,6 @@</span><br><span> return mgcp->actual.endpoint_domain_name[0] ? mgcp->actual.endpoint_domain_name : "mgw";</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static const char *_mgcp_client_name_append_domain(const struct mgcp_client *mgcp, char *name)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- static char endpoint[MGCP_ENDPOINT_MAXLEN];</span><br><span style="color: hsl(0, 100%, 40%);">- int rc;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- rc = snprintf(endpoint, sizeof(endpoint), "%s@%s", name, mgcp_client_endpoint_domain(mgcp));</span><br><span style="color: hsl(0, 100%, 40%);">- if (rc > sizeof(endpoint) - 1) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGP(DLMGCP, LOGL_ERROR, "MGCP endpoint exceeds maximum length of %zu: '%s@%s'\n",</span><br><span style="color: hsl(0, 100%, 40%);">- sizeof(endpoint) - 1, name, mgcp_client_endpoint_domain(mgcp));</span><br><span style="color: hsl(0, 100%, 40%);">- return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- if (rc < 1) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGP(DLMGCP, LOGL_ERROR, "Cannot compose MGCP endpoint name\n");</span><br><span style="color: hsl(0, 100%, 40%);">- return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- return endpoint;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> /*! Compose endpoint name for a wildcarded request to the virtual trunk</span><br><span> * \param[in] mgcp MGCP client descriptor.</span><br><span> * \returns string containing the endpoint name (e.g. rtpbridge\*@mgw) */</span><br><span>diff --git a/src/libosmo-mgcp-client/mgcp_client_vty.c b/src/libosmo-mgcp-client/mgcp_client_vty.c</span><br><span>index cc8db5d..cd12776 100644</span><br><span>--- a/src/libosmo-mgcp-client/mgcp_client_vty.c</span><br><span>+++ b/src/libosmo-mgcp-client/mgcp_client_vty.c</span><br><span>@@ -155,10 +155,71 @@</span><br><span> return CMD_SUCCESS;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_mgw_reset_ep_name,</span><br><span style="color: hsl(120, 100%, 40%);">+ cfg_mgw_reset_ep_name_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+ "mgw reset-endpoint NAME",</span><br><span style="color: hsl(120, 100%, 40%);">+ MGW_STR "Set an eindpoint name that should be reset (DLCX) on startup, e.g. 'rtpbridge/*'\n"</span><br><span style="color: hsl(120, 100%, 40%);">+ "Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct reset_ep *reset_ep;</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* stop when the address is already in the list */</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(reset_ep, &global_mgcp_client_conf->reset_epnames, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (strcmp(argv[0], reset_ep->name) == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, "%% duplicate endpoint name configured ('%s')%s", argv[0], VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+ return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* the domain name is not part of the actual endpoint name */</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < strlen(argv[0]); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (argv[0][i] == '@') {</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, "%% the endpoint name must be given without domain name ('%s')%s",</span><br><span style="color: hsl(120, 100%, 40%);">+ argv[0], VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+ return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ reset_ep = talloc_zero(global_mgcp_client_ctx, struct reset_ep);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(reset_ep);</span><br><span style="color: hsl(120, 100%, 40%);">+ reset_ep->name = talloc_strdup(reset_ep, argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(reset_ep->name);</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_add_tail(&reset_ep->list, &global_mgcp_client_conf->reset_epnames);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_mgw_no_reset_ep_name,</span><br><span style="color: hsl(120, 100%, 40%);">+ cfg_mgw_no_reset_ep_name_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+ "no mgw reset-endpoint NAME",</span><br><span style="color: hsl(120, 100%, 40%);">+ MGW_STR "Do not reset (DLCX) endpoint on startup, e.g. 'rtpbridge/*'\n"</span><br><span style="color: hsl(120, 100%, 40%);">+ "Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct reset_ep *reset_ep;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct reset_ep *reset_ep_del = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(reset_ep, &global_mgcp_client_conf->reset_epnames, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (strcmp(argv[0], reset_ep->name) == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ reset_ep_del = reset_ep;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (reset_ep_del) {</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_del(&reset_ep_del->list);</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(reset_ep_del);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, "%% no such endpoint name configured ('%s')%s", argv[0], VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+ return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> int mgcp_client_config_write(struct vty *vty, const char *indent)</span><br><span> {</span><br><span> const char *addr;</span><br><span> int port;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct reset_ep *reset_ep;</span><br><span> </span><br><span> addr = global_mgcp_client_conf->local_addr;</span><br><span> if (addr)</span><br><span>@@ -182,6 +243,9 @@</span><br><span> vty_out(vty, "%smgw endpoint-domain %s%s", indent,</span><br><span> global_mgcp_client_conf->endpoint_domain_name, VTY_NEWLINE);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(reset_ep, &global_mgcp_client_conf->reset_epnames, list)</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, "%smgw reset-endpoint %s%s", indent, reset_ep->name, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> return CMD_SUCCESS;</span><br><span> }</span><br><span> </span><br><span>@@ -197,6 +261,8 @@</span><br><span> install_lib_element(node, &cfg_mgw_endpoint_range_cmd);</span><br><span> install_lib_element(node, &cfg_mgw_rtp_bts_base_port_cmd);</span><br><span> install_lib_element(node, &cfg_mgw_endpoint_domain_name_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+ install_lib_element(node, &cfg_mgw_reset_ep_name_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+ install_lib_element(node, &cfg_mgw_no_reset_ep_name_cmd);</span><br><span> </span><br><span> /* deprecated 'mgcpgw' commands */</span><br><span> install_lib_element(node, &cfg_mgcpgw_local_ip_cmd);</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-mgw/+/25008">change 25008</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-mgw/+/25008"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: osmo-mgw </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I47e7ff858d5067b46d52329be5f362ff61c0dff8 </div>
<div style="display:none"> Gerrit-Change-Number: 25008 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: dexter <pmaier@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>