aboutsummaryrefslogtreecommitdiffstats
path: root/src/ctrl
diff options
context:
space:
mode:
Diffstat (limited to 'src/ctrl')
-rw-r--r--src/ctrl/Makefile.am8
-rw-r--r--src/ctrl/control_cmd.c106
-rw-r--r--src/ctrl/control_if.c169
-rw-r--r--src/ctrl/control_vty.c21
-rw-r--r--src/ctrl/libosmoctrl.map3
5 files changed, 209 insertions, 98 deletions
diff --git a/src/ctrl/Makefile.am b/src/ctrl/Makefile.am
index ca642869..9d3254c1 100644
--- a/src/ctrl/Makefile.am
+++ b/src/ctrl/Makefile.am
@@ -1,9 +1,10 @@
# This is _NOT_ the library release version, it's an API version.
# Please read chapter "Library interface versions" of the libtool documentation
# before making any modifications: https://www.gnu.org/software/libtool/manual/html_node/Versioning.html
-LIBVERSION=4:0:4
+LIBVERSION=9:0:9
-AM_CFLAGS = -Wall $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)/include $(TALLOC_CFLAGS)
+AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_builddir)
+AM_CFLAGS = -Wall $(TALLOC_CFLAGS)
if ENABLE_CTRL
lib_LTLIBRARIES = libosmoctrl.la
@@ -12,7 +13,7 @@ libosmoctrl_la_SOURCES = control_cmd.c control_if.c fsm_ctrl_commands.c
libosmoctrl_la_LDFLAGS = $(LTLDFLAGS_OSMOCTRL) -version-info $(LIBVERSION) -no-undefined
libosmoctrl_la_LIBADD = $(TALLOC_LIBS) \
- $(top_builddir)/src/libosmocore.la \
+ $(top_builddir)/src/core/libosmocore.la \
$(top_builddir)/src/gsm/libosmogsm.la \
$(top_builddir)/src/vty/libosmovty.la
@@ -21,5 +22,6 @@ libosmoctrl_la_SOURCES += control_vty.c
endif
EXTRA_DIST = libosmoctrl.map
+EXTRA_libosmoctrl_la_DEPENDENCIES = libosmoctrl.map
endif
diff --git a/src/ctrl/control_cmd.c b/src/ctrl/control_cmd.c
index 33496bd8..db205510 100644
--- a/src/ctrl/control_cmd.c
+++ b/src/ctrl/control_cmd.c
@@ -20,10 +20,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
*/
#include <ctype.h>
@@ -35,6 +31,7 @@
#include <unistd.h>
#include <osmocom/ctrl/control_cmd.h>
+#include <osmocom/ctrl/control_if.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/talloc.h>
@@ -207,13 +204,23 @@ failure:
}
/*! Install a given command definition at a given CTRL node.
- * \param[in] node CTRL node at whihc \a cmd is to be installed
+ * \param[in] node CTRL node at which \a cmd is to be installed
* \param[in] cmd command definition to be installed
* \returns 0 on success; negative on error */
int ctrl_cmd_install(enum ctrl_node_type node, struct ctrl_cmd_element *cmd)
{
vector cmds_vec;
+ /* If this assert triggers, it means the program forgot to initialize
+ * the CTRL interface first by calling ctrl_handle_alloc(2)() directly
+ * or indirectly through ctrl_interface_setup_dynip(2)()
+ */
+ if (!ctrl_node_vec) {
+ LOGP(DLCTRL, LOGL_ERROR,
+ "ctrl_handle must be initialized prior to installing cmds.\n");
+ return -ENODEV;
+ }
+
cmds_vec = vector_lookup_ensure(ctrl_node_vec, node);
if (!cmds_vec) {
@@ -516,92 +523,61 @@ err:
* \returns callee-allocated message buffer containing the encoded \a cmd; NULL on error */
struct msgb *ctrl_cmd_make(struct ctrl_cmd *cmd)
{
- struct msgb *msg;
+ struct msgb *msg = NULL;
+ char *strbuf;
+ size_t len;
const char *type;
- char *tmp;
if (!cmd->id)
return NULL;
- msg = msgb_alloc_headroom(4096, 128, "ctrl command make");
- if (!msg)
- return NULL;
-
type = get_value_string(ctrl_type_vals, cmd->type);
switch (cmd->type) {
case CTRL_TYPE_GET:
if (!cmd->variable)
- goto err;
-
- tmp = talloc_asprintf(cmd, "%s %s %s", type, cmd->id, cmd->variable);
- if (!tmp) {
- LOGP(DLCTRL, LOGL_ERROR, "Failed to allocate cmd.\n");
- goto err;
- }
-
- msg->l2h = msgb_put(msg, strlen(tmp));
- memcpy(msg->l2h, tmp, strlen(tmp));
- talloc_free(tmp);
+ return NULL;
+ strbuf = talloc_asprintf(cmd, "%s %s %s", type, cmd->id, cmd->variable);
break;
case CTRL_TYPE_SET:
if (!cmd->variable || !cmd->value)
- goto err;
-
- tmp = talloc_asprintf(cmd, "%s %s %s %s", type, cmd->id, cmd->variable,
- cmd->value);
- if (!tmp) {
- LOGP(DLCTRL, LOGL_ERROR, "Failed to allocate cmd.\n");
- goto err;
- }
-
- msg->l2h = msgb_put(msg, strlen(tmp));
- memcpy(msg->l2h, tmp, strlen(tmp));
- talloc_free(tmp);
+ return NULL;
+ strbuf = talloc_asprintf(cmd, "%s %s %s %s", type, cmd->id,
+ cmd->variable, cmd->value);
break;
case CTRL_TYPE_GET_REPLY:
case CTRL_TYPE_SET_REPLY:
case CTRL_TYPE_TRAP:
if (!cmd->variable || !cmd->reply)
- goto err;
-
- tmp = talloc_asprintf(cmd, "%s %s %s %s", type, cmd->id, cmd->variable,
- cmd->reply);
- if (!tmp) {
- LOGP(DLCTRL, LOGL_ERROR, "Failed to allocate cmd.\n");
- goto err;
- }
-
- msg->l2h = msgb_put(msg, strlen(tmp));
- memcpy(msg->l2h, tmp, strlen(tmp));
- talloc_free(tmp);
+ return NULL;
+ strbuf = talloc_asprintf(cmd, "%s %s %s %s", type, cmd->id,
+ cmd->variable, cmd->reply);
break;
case CTRL_TYPE_ERROR:
if (!cmd->reply)
- goto err;
-
- tmp = talloc_asprintf(cmd, "%s %s %s", type, cmd->id,
- cmd->reply);
- if (!tmp) {
- LOGP(DLCTRL, LOGL_ERROR, "Failed to allocate cmd.\n");
- goto err;
- }
-
- msg->l2h = msgb_put(msg, strlen(tmp));
- memcpy(msg->l2h, tmp, strlen(tmp));
- talloc_free(tmp);
+ return NULL;
+ strbuf = talloc_asprintf(cmd, "%s %s %s", type, cmd->id, cmd->reply);
break;
default:
LOGP(DLCTRL, LOGL_NOTICE, "Unknown command type %i\n", cmd->type);
- goto err;
- break;
+ return NULL;
}
- return msg;
+ if (!strbuf) {
+ LOGP(DLCTRL, LOGL_ERROR, "Failed to allocate cmd.\n");
+ goto ret;
+ }
+ len = strlen(strbuf);
-err:
- msgb_free(msg);
- return NULL;
+ msg = msgb_alloc_headroom(len + 128, 128, "ctrl ERROR command make");
+ if (!msg)
+ goto ret;
+ msg->l2h = msgb_put(msg, len);
+ memcpy(msg->l2h, strbuf, len);
+
+ret:
+ talloc_free(strbuf);
+ return msg;
}
/*! Build a deferred control command state and keep it the per-connection list of deferred commands.
@@ -672,7 +648,7 @@ int ctrl_cmd_def_send(struct ctrl_cmd_def *cd)
cmd->type = CTRL_TYPE_ERROR;
}
- rc = ctrl_cmd_send(&cmd->ccon->write_queue, cmd);
+ rc = ctrl_cmd_send2(cmd->ccon, cmd);
talloc_free(cmd);
llist_del(&cd->list);
diff --git a/src/ctrl/control_if.c b/src/ctrl/control_if.c
index ce2e3676..c265c3a9 100644
--- a/src/ctrl/control_if.c
+++ b/src/ctrl/control_if.c
@@ -20,10 +20,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
*/
#include "config.h"
@@ -35,6 +31,7 @@
#include <string.h>
#include <time.h>
#include <unistd.h>
+#include <limits.h>
#include <arpa/inet.h>
@@ -50,9 +47,11 @@
#include <osmocom/ctrl/control_cmd.h>
#include <osmocom/ctrl/control_if.h>
+#include <osmocom/ctrl/control_vty.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/rate_ctr.h>
+#include <osmocom/core/stat_item.h>
#include <osmocom/core/select.h>
#include <osmocom/core/counter.h>
#include <osmocom/core/talloc.h>
@@ -82,26 +81,22 @@ static LLIST_HEAD(ctrl_lookup_helpers);
* \returns 1 on success; 0 in case of error */
int ctrl_parse_get_num(vector vline, int i, long *num)
{
- char *token, *tmp;
+ char *token;
+ int64_t val;
if (i >= vector_active(vline))
return 0;
token = vector_slot(vline, i);
- errno = 0;
- if (token[0] == '\0')
- return 0;
-
- *num = strtol(token, &tmp, 10);
- if (tmp[0] != '\0' || errno != 0)
+ if (osmo_str_to_int64(&val, token, 10, LONG_MIN, LONG_MAX))
return 0;
-
+ *num = (long)val;
return 1;
}
/*! Send a CTRL command to all connections.
* \param[in] ctrl global control handle
- * \param[in] cmd command to send to all connections in \ctrl
+ * \param[in] cmd command to send to all connections in ctrl
* \returns number of times the command has been sent */
int ctrl_cmd_send_to_all(struct ctrl_handle *ctrl, struct ctrl_cmd *cmd)
{
@@ -111,18 +106,28 @@ int ctrl_cmd_send_to_all(struct ctrl_handle *ctrl, struct ctrl_cmd *cmd)
llist_for_each_entry(ccon, &ctrl->ccon_list, list_entry) {
if (ccon == cmd->ccon)
continue;
- if (ctrl_cmd_send(&ccon->write_queue, cmd))
+ if (ctrl_cmd_send2(ccon, cmd))
ret++;
}
return ret;
}
-/*! Encode a CTRL command and append it to the given write queue
+/*! Encode a CTRL command and append it to the given ctrl_connection
* \param[inout] queue write queue to which encoded \a cmd shall be appended
* \param[in] cmd decoded command representation
* \returns 0 in case of success; negative on error */
int ctrl_cmd_send(struct osmo_wqueue *queue, struct ctrl_cmd *cmd)
{
+ struct ctrl_connection *ccon = container_of(queue, struct ctrl_connection, write_queue);
+ return ctrl_cmd_send2(ccon, cmd);
+}
+
+/*! Encode a CTRL command and append it to the given ctrl_connection
+ * \param[inout] queue write queue to which encoded \a cmd shall be appended
+ * \param[in] cmd decoded command representation
+ * \returns 0 in case of success; negative on error */
+int ctrl_cmd_send2(struct ctrl_connection *ccon, struct ctrl_cmd *cmd)
+{
int ret;
struct msgb *msg;
@@ -135,7 +140,7 @@ int ctrl_cmd_send(struct osmo_wqueue *queue, struct ctrl_cmd *cmd)
ipa_prepend_header_ext(msg, IPAC_PROTO_EXT_CTRL);
ipa_prepend_header(msg, IPAC_PROTO_OSMO);
- ret = osmo_wqueue_enqueue(queue, msg);
+ ret = osmo_wqueue_enqueue(&ccon->write_queue, msg);
if (ret != 0) {
LOGP(DLCTRL, LOGL_ERROR, "Failed to enqueue the command.\n");
msgb_free(msg);
@@ -221,6 +226,10 @@ int ctrl_cmd_handle(struct ctrl_handle *ctrl, struct ctrl_cmd *cmd,
if (cmd->type == CTRL_TYPE_SET_REPLY ||
cmd->type == CTRL_TYPE_GET_REPLY) {
+ if (ctrl->reply_cb) {
+ ctrl->reply_cb(ctrl, cmd, data);
+ return CTRL_CMD_HANDLED;
+ }
if (strncmp(cmd->reply, "OK", 2) == 0) {
LOGP(DLCTRL, LOGL_DEBUG, "%s <%s> for %s is OK\n",
get_value_string(ctrl_type_vals, cmd->type),
@@ -465,7 +474,7 @@ int ctrl_handle_msg(struct ctrl_handle *ctrl, struct ctrl_connection *ccon, stru
send_reply:
/* There is a reply or error that should be reported back to the sender. */
- ctrl_cmd_send(&ccon->write_queue, cmd);
+ ctrl_cmd_send2(ccon, cmd);
just_free:
talloc_free(cmd);
return 0;
@@ -485,8 +494,14 @@ static int control_write_cb(struct osmo_fd *bfd, struct msgb *msg)
control_close_conn(ccon);
return -EBADF;
}
- if (rc != msg->len)
+ if (rc < 0) {
LOGP(DLCTRL, LOGL_ERROR, "Failed to write message to the CTRL connection.\n");
+ return 0;
+ }
+ if (rc < msg->len) {
+ msgb_pull(msg, rc);
+ return -EAGAIN;
+ }
return 0;
}
@@ -510,6 +525,7 @@ struct ctrl_connection *osmo_ctrl_conn_alloc(void *ctx, void *data)
INIT_LLIST_HEAD(&ccon->def_cmds);
ccon->write_queue.bfd.data = data;
+ ccon->write_queue.bfd.fd = -1;
ccon->write_queue.write_cb = control_write_cb;
ccon->write_queue.read_cb = handle_control_read;
@@ -584,12 +600,12 @@ static uint64_t get_rate_ctr_value(const struct rate_ctr *ctr, int intv, const c
}
}
-static int get_rate_ctr_group_idx(const struct rate_ctr_group *ctrg, int intv, struct ctrl_cmd *cmd)
+static int get_rate_ctr_group_idx(struct rate_ctr_group *ctrg, int intv, struct ctrl_cmd *cmd)
{
unsigned int i;
for (i = 0; i < ctrg->desc->num_ctr; i++) {
ctrl_cmd_reply_printf(cmd, "%s %"PRIu64";", ctrg->desc->ctr_desc[i].name,
- get_rate_ctr_value(&ctrg->ctr[i], intv, ctrg->desc->group_name_prefix));
+ get_rate_ctr_value(rate_ctr_group_get_ctr(ctrg, i), intv, ctrg->desc->group_name_prefix));
if (!cmd->reply) {
cmd->reply = "OOM";
return CTRL_CMD_ERROR;
@@ -718,6 +734,100 @@ static int verify_rate_ctr(struct ctrl_cmd *cmd, const char *value, void *data)
return 0;
}
+/* Expose all stat_item groups on CTRL, as read-only variables of the form:
+ * stat_item.(last|...).group_name.N.item_name
+ * stat_item.(last|...).group_name.by_name.group_idx_name.item_name
+ */
+CTRL_CMD_DEFINE_RO(stat_item, "stat_item *");
+static int get_stat_item(struct ctrl_cmd *cmd, void *data)
+{
+ char *dup;
+ char *saveptr;
+ char *value_type;
+ char *group_name;
+ char *group_idx_str;
+ char *item_name;
+ char *tmp;
+ int32_t val;
+ struct osmo_stat_item_group *statg;
+ const struct osmo_stat_item *stat_item;
+
+ /* cmd will be freed in control_if.c after handling here, so no need to free the dup string. */
+ dup = talloc_strdup(cmd, cmd->variable);
+ if (!dup) {
+ cmd->reply = "OOM";
+ return CTRL_CMD_ERROR;
+ }
+
+ /* Split off the first "stat_item." part */
+ tmp = strtok_r(dup, ".", &saveptr);
+ if (!tmp || strcmp(tmp, "stat_item") != 0)
+ goto format_error;
+
+ /* Split off the "last." part (validated further below) */
+ value_type = strtok_r(NULL, ".", &saveptr);
+ if (!value_type)
+ goto format_error;
+
+ /* Split off the "group_name." part */
+ group_name = strtok_r(NULL, ".", &saveptr);
+ if (!group_name)
+ goto format_error;
+
+ /* Split off the "N." part */
+ group_idx_str = strtok_r(NULL, ".", &saveptr);
+ if (!group_idx_str)
+ goto format_error;
+ if (strcmp(group_idx_str, "by_name") == 0) {
+ /* The index is not given by "N" but by "by_name.foo". Get the "foo" idx-name */
+ group_idx_str = strtok_r(NULL, ".", &saveptr);
+ statg = osmo_stat_item_get_group_by_name_idxname(group_name, group_idx_str);
+ } else {
+ int idx;
+ if (osmo_str_to_int(&idx, group_idx_str, 10, 0, INT_MAX))
+ goto format_error;
+ statg = osmo_stat_item_get_group_by_name_idx(group_name, idx);
+ }
+ if (!statg) {
+ cmd->reply = "Stat group with given name and index not found";
+ return CTRL_CMD_ERROR;
+ }
+
+ /* Split off the "item_name" part */
+ item_name = strtok_r(NULL, ".", &saveptr);
+ if (!item_name)
+ goto format_error;
+ stat_item = osmo_stat_item_get_by_name(statg, item_name);
+ if (!stat_item) {
+ cmd->reply = "No such stat item found";
+ return CTRL_CMD_ERROR;
+ }
+
+ tmp = strtok_r(NULL, "", &saveptr);
+ if (tmp) {
+ cmd->reply = "Garbage after stat item name";
+ return CTRL_CMD_ERROR;
+ }
+
+ if (!strcmp(value_type, "last"))
+ val = osmo_stat_item_get_last(stat_item);
+ else
+ goto format_error;
+
+ cmd->reply = talloc_asprintf(cmd, "%"PRIu32, val);
+ if (!cmd->reply) {
+ cmd->reply = "OOM";
+ return CTRL_CMD_ERROR;
+ }
+
+ return CTRL_CMD_REPLY;
+
+format_error:
+ cmd->reply = "Stat item must be of form stat_item.type.group_name.N.item_name,"
+ " e.g. 'stat_item.last.bsc.0.msc_num:connected'";
+ return CTRL_CMD_ERROR;
+}
+
/* counter */
CTRL_CMD_DEFINE(counter, "counter *");
static int get_counter(struct ctrl_cmd *cmd, void *data)
@@ -779,7 +889,7 @@ static int verify_counter(struct ctrl_cmd *cmd, const char *value, void *data)
struct ctrl_handle *ctrl_interface_setup(void *data, uint16_t port,
ctrl_cmd_lookup lookup)
{
- return ctrl_interface_setup_dynip(data, "127.0.0.1", port, lookup);
+ return ctrl_interface_setup2(data, port, lookup, 0);
}
static int ctrl_initialized = 0;
@@ -805,6 +915,9 @@ static int ctrl_init(unsigned int node_count)
ret = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_rate_ctr);
if (ret)
goto err_vec;
+ ret = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_stat_item);
+ if (ret)
+ goto err_vec;
ret = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_counter);
if (ret)
goto err_vec;
@@ -928,12 +1041,24 @@ struct ctrl_handle *ctrl_interface_setup_dynip(void *data,
return ctrl_interface_setup_dynip2(data, bind_addr, port, lookup, 0);
}
+/*! Initializes CTRL interface using the configured bind addr/port.
+ * \param[in] data Pointer which will be made available to each set_..() get_..() verify_..() control command function
+ * \param[in] default_port TCP port number to bind to if not explicitly configured
+ * \param[in] lookup Lookup function pointer, can be NULL
+ * \param[in] node_count Number of CTRL nodes to allocate, 0 for default.
+ */
+struct ctrl_handle *ctrl_interface_setup2(void *data, uint16_t default_port, ctrl_cmd_lookup lookup,
+ unsigned int node_count)
+{
+ return ctrl_interface_setup_dynip2(data, ctrl_vty_get_bind_addr(), ctrl_vty_get_bind_port(default_port), lookup,
+ node_count);
+}
/*! Install a lookup helper function for control nodes
* This function is used by e.g. library code to install lookup helpers
* for additional nodes in the control interface.
* \param[in] lookup The lookup helper function
- * \retuns - on success; negative on error.
+ * \returns - on success; negative on error.
*/
int ctrl_lookup_register(ctrl_cmd_lookup lookup)
{
diff --git a/src/ctrl/control_vty.c b/src/ctrl/control_vty.c
index ef988892..a7ebddc2 100644
--- a/src/ctrl/control_vty.c
+++ b/src/ctrl/control_vty.c
@@ -17,10 +17,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
*/
#include <stdlib.h>
@@ -30,16 +26,20 @@
static void *ctrl_vty_ctx = NULL;
static const char *ctrl_vty_bind_addr = NULL;
+/* Port the CTRL should bind to: -1 means not configured */
+static int ctrl_bind_port = -1;
DEFUN(cfg_ctrl_bind_addr,
cfg_ctrl_bind_addr_cmd,
- "bind A.B.C.D",
+ "bind A.B.C.D [<0-65535>]",
"Set bind address to listen for Control connections\n"
- "Local IP address (default 127.0.0.1)\n")
+ "Local IP address (default 127.0.0.1)\n"
+ "Local TCP port number\n")
{
talloc_free((char*)ctrl_vty_bind_addr);
ctrl_vty_bind_addr = NULL;
ctrl_vty_bind_addr = talloc_strdup(ctrl_vty_ctx, argv[0]);
+ ctrl_bind_port = argc > 1 ? atoi(argv[1]) : -1;
return CMD_SUCCESS;
}
@@ -50,6 +50,11 @@ const char *ctrl_vty_get_bind_addr(void)
return ctrl_vty_bind_addr;
}
+uint16_t ctrl_vty_get_bind_port(uint16_t default_port)
+{
+ return ctrl_bind_port >= 0 ? ctrl_bind_port : default_port;
+}
+
static struct cmd_node ctrl_node = {
L_CTRL_NODE,
"%s(config-ctrl)# ",
@@ -82,10 +87,10 @@ static int config_write_ctrl(struct vty *vty)
int ctrl_vty_init(void *ctx)
{
ctrl_vty_ctx = ctx;
- install_element(CONFIG_NODE, &cfg_ctrl_cmd);
+ install_lib_element(CONFIG_NODE, &cfg_ctrl_cmd);
install_node(&ctrl_node, config_write_ctrl);
- install_element(L_CTRL_NODE, &cfg_ctrl_bind_addr_cmd);
+ install_lib_element(L_CTRL_NODE, &cfg_ctrl_bind_addr_cmd);
return 0;
}
diff --git a/src/ctrl/libosmoctrl.map b/src/ctrl/libosmoctrl.map
index f995467b..3418e620 100644
--- a/src/ctrl/libosmoctrl.map
+++ b/src/ctrl/libosmoctrl.map
@@ -15,6 +15,7 @@ ctrl_cmd_parse;
ctrl_cmd_parse2;
ctrl_cmd_parse3;
ctrl_cmd_send;
+ctrl_cmd_send2;
ctrl_cmd_send_to_all;
ctrl_cmd_send_trap;
ctrl_cmd_trap;
@@ -22,12 +23,14 @@ ctrl_handle_alloc; /* could be removed? */
ctrl_handle_alloc2; /* could be removed? */
ctrl_handle_msg; /* only used in unit test */
ctrl_interface_setup;
+ctrl_interface_setup2;
ctrl_interface_setup_dynip;
ctrl_interface_setup_dynip2;
ctrl_lookup_register;
ctrl_parse_get_num;
ctrl_type_vals;
ctrl_vty_get_bind_addr;
+ctrl_vty_get_bind_port;
ctrl_vty_init;
osmo_ctrl_conn_alloc;