From 31c0fef2fd5daa53617c05752411ec6446d8a82b Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 16 Apr 2017 17:26:30 +0200 Subject: control_if: Add control interface commands for FSMs This allows programmatic access to introspection of FSM instances, which is quite handy from e.g. external test cases: Send a message to the code, then use the CTRL interface to check if that message has triggered the right kind of state transition. Change-Id: I0f80340ee9c61c88962fdd6764a6098a844d0d1e --- src/ctrl/Makefile.am | 2 +- src/ctrl/control_if.c | 4 + src/ctrl/fsm_ctrl_commands.c | 175 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 src/ctrl/fsm_ctrl_commands.c (limited to 'src/ctrl') diff --git a/src/ctrl/Makefile.am b/src/ctrl/Makefile.am index 1817caca..e8d55e6b 100644 --- a/src/ctrl/Makefile.am +++ b/src/ctrl/Makefile.am @@ -8,7 +8,7 @@ AM_CFLAGS = -Wall $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)/incl if ENABLE_CTRL lib_LTLIBRARIES = libosmoctrl.la -libosmoctrl_la_SOURCES = control_cmd.c control_if.c +libosmoctrl_la_SOURCES = control_cmd.c control_if.c fsm_ctrl_commands.c libosmoctrl_la_LDFLAGS = $(LTLDFLAGS_OSMOCTRL) $(TALLOC_LIBS) -version-info $(LIBVERSION) -no-undefined libosmoctrl_la_LIBADD = \ diff --git a/src/ctrl/control_if.c b/src/ctrl/control_if.c index c8b47226..6ab34c7b 100644 --- a/src/ctrl/control_if.c +++ b/src/ctrl/control_if.c @@ -717,6 +717,10 @@ static int ctrl_init(void) if (ret) goto err_vec; + ret = osmo_fsm_ctrl_cmds_install(); + if (ret) + goto err_vec; + ctrl_initialized = 1; return 0; diff --git a/src/ctrl/fsm_ctrl_commands.c b/src/ctrl/fsm_ctrl_commands.c new file mode 100644 index 00000000..0dfc3962 --- /dev/null +++ b/src/ctrl/fsm_ctrl_commands.c @@ -0,0 +1,175 @@ +#include +#include + +#include + +#include +#include + +/*! \brief control interface lookup function for FSM's + * \param[in] data Private data passed to controlif_setup() + * \param[in] vline Vector of the line holding the command string + * \param[out] node_type type (CTRL_NODE_) that was determined + * \param[out] node_data private data of node that was determined + * \param i Current index into vline, up to which it is parsed + */ +static int fsm_ctrl_node_lookup(void *data, vector vline, int *node_type, + void **node_data, int *i) +{ + struct osmo_fsm *fsm = NULL; + struct osmo_fsm_inst *fi = NULL;; + const char *token = vector_slot(vline, *i); + + switch (*node_type) { + case CTRL_NODE_ROOT: + if (!strcmp(token, "fsm")) { + const char *fsm_name; + (*i)++; + fsm_name = vector_lookup(vline, *i); + if (!fsm_name) + goto err_index; + fsm = osmo_fsm_find_by_name(fsm_name); + if (!fsm) + goto err_missing; + *node_data = fsm; + *node_type = CTRL_NODE_FSM; + } + break; + case CTRL_NODE_FSM: + fsm = *node_data; + if (!strcmp(token, "name")) { + const char *inst_name; + (*i)++; + inst_name = vector_lookup(vline, *i); + if (!inst_name) + goto err_index; + fi = osmo_fsm_inst_find_by_name(fsm, inst_name); + if (!fi) + goto err_missing; + *node_data = fi; + *node_type = CTRL_NODE_FSM_INST; + } else if (!strcmp(token, "id")) { + const char *inst_id; + (*i)++; + inst_id = vector_lookup(vline, *i); + if (!inst_id) + goto err_index; + fi = osmo_fsm_inst_find_by_id(fsm, inst_id); + if (!fi) + goto err_missing; + *node_data = fi; + *node_type = CTRL_NODE_FSM_INST; + } + break; + default: + return 0; + } + + return 1; + +err_index: + return -ERANGE; +err_missing: + return -ENODEV; +} + +static int get_fsm_inst_state(struct ctrl_cmd *cmd, void *data) +{ + struct osmo_fsm_inst *fi = cmd->node; + + if (!fi) { + cmd->reply = "No such FSM found"; + return CTRL_CMD_ERROR; + } + + cmd->reply = talloc_strdup(cmd, osmo_fsm_state_name(fi->fsm, fi->state)); + return CTRL_CMD_REPLY; +} +CTRL_CMD_DEFINE_RO(fsm_inst_state, "state"); + +static int get_fsm_inst_parent_name(struct ctrl_cmd *cmd, void *data) +{ + struct osmo_fsm_inst *fi = cmd->node; + + if (!fi) { + cmd->reply = "No such FSM found"; + return CTRL_CMD_ERROR; + } + if (!fi->proc.parent) { + cmd->reply = "No parent"; + return CTRL_CMD_ERROR; + } + cmd->reply = talloc_strdup(cmd, fi->proc.parent->name); + return CTRL_CMD_REPLY; +} +CTRL_CMD_DEFINE_RO(fsm_inst_parent_name, "parent-name"); + +static int get_fsm_inst_timer(struct ctrl_cmd *cmd, void *data) +{ + struct osmo_fsm_inst *fi = cmd->node; + struct timeval remaining; + + if (!fi) { + cmd->reply = "No such FSM found"; + return CTRL_CMD_ERROR; + } + if (osmo_timer_remaining(&fi->timer, NULL, &remaining) < 0) + cmd->reply = "0,0,0"; + else + cmd->reply = talloc_asprintf(cmd, "%u,%ld,%ld", fi->T, remaining.tv_sec, remaining.tv_usec); + + return CTRL_CMD_REPLY; +} +CTRL_CMD_DEFINE_RO(fsm_inst_timer, "timer"); + + +static int get_fsm_inst_dump(struct ctrl_cmd *cmd, void *data) +{ + struct osmo_fsm_inst *fi = cmd->node; + struct osmo_fsm_inst *child; + + if (!fi) { + cmd->reply = "No such FSM found"; + return CTRL_CMD_ERROR; + } + + /* Fixed Part: Name, ID, log_level, state, timer number */ + cmd->reply = talloc_asprintf(cmd, "'%s','%s','%s','%s',%u", fi->name, fi->id, + log_level_str(fi->log_level), + osmo_fsm_state_name(fi->fsm, fi->state), fi->T); + + /* Variable Parts below */ + if (fi->T) { + struct timeval remaining; + int rc; + rc = osmo_timer_remaining(&fi->timer, NULL, &remaining); + if (rc == 0) { + cmd->reply = talloc_asprintf_append(cmd->reply, ",timeout_sec=%ld,timeout_usec=%ld", + remaining.tv_sec, remaining.tv_usec); + } + } + + if (fi->proc.parent) + cmd->reply = talloc_asprintf_append(cmd->reply, ",parent='%s'", fi->proc.parent->name); + + llist_for_each_entry(child, &fi->proc.children, list) { + cmd->reply = talloc_asprintf_append(cmd->reply, ",child='%s'", child->name); + } + + return CTRL_CMD_REPLY; +} + +CTRL_CMD_DEFINE_RO(fsm_inst_dump, "dump"); + +int osmo_fsm_ctrl_cmds_install(void) +{ + int rc = 0; + + rc |= ctrl_cmd_install(CTRL_NODE_FSM_INST, &cmd_fsm_inst_dump); + rc |= ctrl_cmd_install(CTRL_NODE_FSM_INST, &cmd_fsm_inst_state); + rc |= ctrl_cmd_install(CTRL_NODE_FSM_INST, &cmd_fsm_inst_parent_name); + rc |= ctrl_cmd_install(CTRL_NODE_FSM_INST, &cmd_fsm_inst_timer); + rc |= ctrl_lookup_register(fsm_ctrl_node_lookup); + + return rc; +} -- cgit v1.2.3