diff options
| author | Harald Welte <laforge@gnumonks.org> | 2017-04-16 17:26:30 +0200 | 
|---|---|---|
| committer | Harald Welte <laforge@gnumonks.org> | 2017-04-27 09:50:47 +0200 | 
| commit | 31c0fef2fd5daa53617c05752411ec6446d8a82b (patch) | |
| tree | 299c1643f09720801ae43b0936463e9d2d69b0a7 /src | |
| parent | f85861d6eb6ebc962bc710ac2d481536e6be7053 (diff) | |
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
Diffstat (limited to 'src')
| -rw-r--r-- | src/ctrl/Makefile.am | 2 | ||||
| -rw-r--r-- | src/ctrl/control_if.c | 4 | ||||
| -rw-r--r-- | src/ctrl/fsm_ctrl_commands.c | 175 | 
3 files changed, 180 insertions, 1 deletions
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 <string.h> +#include <errno.h> + +#include <osmocom/core/fsm.h> + +#include <osmocom/ctrl/control_cmd.h> +#include <osmocom/ctrl/control_if.h> + +/*! \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; +}  | 
