<p>laforge <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/osmo-mgw/+/25008">View Change</a></p><div style="white-space:pre-wrap">Approvals:
Jenkins Builder: Verified
osmith: Looks good to me, but someone else must approve
laforge: Looks good to me, approved
</div><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 TODO-RELEASE<br>M include/osmocom/mgcp_client/mgcp_client.h<br>M include/osmocom/mgcp_client/mgcp_client_internal.h<br>M src/libosmo-mgcp-client/mgcp_client.c<br>M src/libosmo-mgcp-client/mgcp_client_vty.c<br>5 files changed, 135 insertions(+), 20 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/TODO-RELEASE b/TODO-RELEASE</span><br><span>index add44f1..3b31cde 100644</span><br><span>--- a/TODO-RELEASE</span><br><span>+++ b/TODO-RELEASE</span><br><span>@@ -25,3 +25,4 @@</span><br><span> #</span><br><span> #library what description / commit summary line</span><br><span> update dependency to libosmocore > 1.5.1 for our use of osmo_sock_set_dscp()</span><br><span style="color: hsl(120, 100%, 40%);">+libosmo-mgcp-client struct mgcp_client_conf ABI breackage</span><br><span>\ No newline at end of file</span><br><span>diff --git a/include/osmocom/mgcp_client/mgcp_client.h b/include/osmocom/mgcp_client/mgcp_client.h</span><br><span>index 02996a7..e9fe0ae 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>@@ -26,6 +26,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/include/osmocom/mgcp_client/mgcp_client_internal.h b/include/osmocom/mgcp_client/mgcp_client_internal.h</span><br><span>index b4b3b02..44b9022 100644</span><br><span>--- a/include/osmocom/mgcp_client/mgcp_client_internal.h</span><br><span>+++ b/include/osmocom/mgcp_client/mgcp_client_internal.h</span><br><span>@@ -4,6 +4,12 @@</span><br><span> </span><br><span> #define MSGB_CB_MGCP_TRANS_ID 0</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[MGCP_ENDPOINT_MAXLEN];</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct mgcp_client {</span><br><span> struct mgcp_client_conf actual;</span><br><span> struct osmo_wqueue wq;</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 69d687b..440cd96 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>@@ -200,6 +200,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>@@ -753,6 +755,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>@@ -783,6 +787,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(mgcp, 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>@@ -822,13 +832,49 @@</span><br><span> return -EINVAL;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/*! Initalize client connection (opens socket only, no request is sent yet)</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%);">+static 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%);">+/* Format 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%);">+{</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 style="color: hsl(120, 100%, 40%);">+static const char *_mgcp_client_name_append_domain(const struct mgcp_client *mgcp, const 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%);">+/*! Initialize client connection (opens socket)</span><br><span> * \param[in,out] mgcp MGCP client descriptor.</span><br><span> * \returns 0 on success, -EINVAL on error. */</span><br><span> int mgcp_client_connect(struct mgcp_client *mgcp)</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 style="color: hsl(120, 100%, 40%);">+ const char *epname;</span><br><span> </span><br><span> if (!mgcp) {</span><br><span> LOGP(DLMGCP, LOGL_FATAL, "MGCPGW client not initialized properly\n");</span><br><span>@@ -851,9 +897,15 @@</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%);">+ epname = _mgcp_client_name_append_domain(mgcp, reset_ep->name);</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DLMGCP, LOGL_INFO, "MGCP GW sending DLCX to: %s\n", epname);</span><br><span style="color: hsl(120, 100%, 40%);">+ _mgcp_client_send_dlcx(mgcp, epname);</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>@@ -893,24 +945,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..1126c5c 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>@@ -29,6 +29,7 @@</span><br><span> #include <osmocom/core/utils.h></span><br><span> </span><br><span> #include <osmocom/mgcp_client/mgcp_client.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mgcp_client/mgcp_client_internal.h></span><br><span> </span><br><span> #define MGW_STR MGCP_CLIENT_MGW_STR</span><br><span> </span><br><span>@@ -155,10 +156,72 @@</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 "Add an endpoint name that should be reset (DLCX) on connect to the reset-endpoint list,"</span><br><span style="color: hsl(120, 100%, 40%);">+ "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%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct reset_ep *reset_ep;</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%);">+ if (strchr(argv[0], '@')) {</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%);">+ 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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = osmo_strlcpy(reset_ep->name, argv[0], sizeof(reset_ep->name));</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc >= sizeof(reset_ep->name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, "%% Error: 'mgw reset-endpoint' name too long, max length is %zu: '%s'%s",</span><br><span style="color: hsl(120, 100%, 40%);">+ sizeof(reset_ep->name) - 1, argv[0], VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(reset_ep);</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%);">+ 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 "remove an endpoint name from the reset-endpoint list, 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%);">+</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%);">+ llist_del(&reset_ep->list);</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(reset_ep);</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%);">+</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> 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 +245,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 +263,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: 17 </div>
<div style="display:none"> Gerrit-Owner: dexter <pmaier@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: daniel <dwillmann@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: osmith <osmith@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-CC: neels <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>