blob: 83a8e791390e250192590413bc6bc7786fb81db2 [file] [log] [blame]
Neels Hofmeyr17518fe2017-06-20 04:35:06 +02001/*
2 * (C) 2016 by Harald Welte <laforge@gnumonks.org>
Harald Welte34193912017-01-07 11:49:55 +01003 * All Rights Reserved
4 *
Harald Weltee08da972017-11-13 01:00:26 +09005 * SPDX-License-Identifier: GPL-2.0+
6 *
Harald Welte34193912017-01-07 11:49:55 +01007 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 */
22
23#include <stdlib.h>
24#include <string.h>
25
26#include "../../config.h"
27
28#include <osmocom/vty/command.h>
29#include <osmocom/vty/buffer.h>
30#include <osmocom/vty/vty.h>
31#include <osmocom/vty/telnet_interface.h>
32#include <osmocom/vty/misc.h>
33
34#include <osmocom/core/fsm.h>
35#include <osmocom/core/logging.h>
36#include <osmocom/core/linuxlist.h>
37
Harald Welte8c648252017-10-16 15:17:03 +020038/*! \file fsm_vty.c
39 * Osmocom FSM introspection via VTY.
Harald Welte96e2a002017-06-12 21:44:18 +020040 *
41 * This is code implementing generic VTY access to Osmocom FSMs from
42 * libosmocore. This means that any application can expose all state
43 * of all instances of all registered FSM classes by calling a single
44 * command during startup: \ref osmo_fsm_vty_add_cmds
45 */
46
Harald Welte34193912017-01-07 11:49:55 +010047/* we don't want to add this to a public header file; this is simply
48 * exported by libosmocore and used by libmsomvty but not for public
49 * consumption. */
50extern struct llist_head osmo_g_fsms;
51
Neels Hofmeyr87e45502017-06-20 00:17:59 +020052/*! Print information about a FSM [class] to the given VTY
Harald Welte34193912017-01-07 11:49:55 +010053 * \param vty The VTY to which to print
Harald Weltecec4bbe2021-01-19 20:55:00 +010054 * \param[in] prefix prefix to print at start of each line (typically indenting)
Harald Welte34193912017-01-07 11:49:55 +010055 * \param[in] fsm The FSM class to print
56 */
Harald Weltecec4bbe2021-01-19 20:55:00 +010057void vty_out_fsm2(struct vty *vty, const char *prefix, struct osmo_fsm *fsm)
Harald Welte34193912017-01-07 11:49:55 +010058{
59 unsigned int i;
60 const struct value_string *evt_name;
61
Harald Weltecec4bbe2021-01-19 20:55:00 +010062 vty_out(vty, "%sFSM Name: '%s', Log Subsys: '%s'%s", prefix, fsm->name,
Harald Welte34193912017-01-07 11:49:55 +010063 log_category_name(fsm->log_subsys), VTY_NEWLINE);
64 /* list the events */
Stefan Sperlingcc817222018-02-26 19:02:30 +010065 if (fsm->event_names) {
66 for (evt_name = fsm->event_names; evt_name->str != NULL; evt_name++) {
Harald Weltecec4bbe2021-01-19 20:55:00 +010067 vty_out(vty, "%s Event %02u (0x%08x): '%s'%s", prefix, evt_name->value,
Stefan Sperlingcc817222018-02-26 19:02:30 +010068 (1 << evt_name->value), evt_name->str, VTY_NEWLINE);
69 }
70 } else
Harald Weltecec4bbe2021-01-19 20:55:00 +010071 vty_out(vty, "%s No event names are defined for this FSM! Please fix!%s", prefix, VTY_NEWLINE);
Stefan Sperlingcc817222018-02-26 19:02:30 +010072
Harald Welte34193912017-01-07 11:49:55 +010073 /* list the states */
Harald Weltecec4bbe2021-01-19 20:55:00 +010074 vty_out(vty, "%s Number of States: %u%s", prefix, fsm->num_states, VTY_NEWLINE);
Harald Welte34193912017-01-07 11:49:55 +010075 for (i = 0; i < fsm->num_states; i++) {
76 const struct osmo_fsm_state *state = &fsm->states[i];
Harald Weltecec4bbe2021-01-19 20:55:00 +010077 vty_out(vty, "%s State %-20s InEvtMask: 0x%08x, OutStateMask: 0x%08x%s", prefix,
Harald Welte34193912017-01-07 11:49:55 +010078 state->name, state->in_event_mask, state->out_state_mask,
79 VTY_NEWLINE);
80 }
81}
82
Harald Weltecec4bbe2021-01-19 20:55:00 +010083/*! Print information about a FSM [class] to the given VTY
84 * \param vty The VTY to which to print
85 * \param[in] fsm The FSM class to print
86 */
87void vty_out_fsm(struct vty *vty, struct osmo_fsm *fsm)
88{
89 vty_out_fsm2(vty, "", fsm);
90}
91
92/*! Print a FSM instance to the given VTY
93 * \param vty The VTY to which to print
94 * \param[in] prefix prefix to print at start of each line (typically indenting)
95 * \param[in] fsmi The FSM instance to print
96 */
97void vty_out_fsm_inst2(struct vty *vty, const char *prefix, struct osmo_fsm_inst *fsmi)
98{
99 struct osmo_fsm_inst *child;
100
101 vty_out(vty, "%sFSM Instance Name: '%s', ID: '%s'%s", prefix,
102 fsmi->name, fsmi->id, VTY_NEWLINE);
103 vty_out(vty, "%s Log-Level: '%s', State: '%s'%s", prefix,
104 log_level_str(fsmi->log_level),
105 osmo_fsm_state_name(fsmi->fsm, fsmi->state),
106 VTY_NEWLINE);
107 if (fsmi->T)
108 vty_out(vty, "%s Timer: %u%s", prefix, fsmi->T, VTY_NEWLINE);
109 if (fsmi->proc.parent) {
110 vty_out(vty, "%s Parent: '%s', Term-Event: '%s'%s", prefix,
111 fsmi->proc.parent->name,
112 osmo_fsm_event_name(fsmi->proc.parent->fsm,
113 fsmi->proc.parent_term_event),
114 VTY_NEWLINE);
115 }
116 llist_for_each_entry(child, &fsmi->proc.children, proc.child) {
117 vty_out(vty, "%s Child: '%s'%s", prefix, child->name, VTY_NEWLINE);
118 }
119}
120
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200121/*! Print a FSM instance to the given VTY
Harald Welte34193912017-01-07 11:49:55 +0100122 * \param vty The VTY to which to print
123 * \param[in] fsmi The FSM instance to print
124 */
125void vty_out_fsm_inst(struct vty *vty, struct osmo_fsm_inst *fsmi)
126{
Harald Weltecec4bbe2021-01-19 20:55:00 +0100127 vty_out_fsm_inst2(vty, "", fsmi);
Harald Welte34193912017-01-07 11:49:55 +0100128}
129
130#define SH_FSM_STR SHOW_STR "Show information about finite state machines\n"
131#define SH_FSMI_STR SHOW_STR "Show information about finite state machine instances\n"
132
133DEFUN(show_fsms, show_fsms_cmd,
134 "show fsm all",
135 SH_FSM_STR
136 "Display a list of all registered finite state machines\n")
137{
138 struct osmo_fsm *fsm;
139
140 llist_for_each_entry(fsm, &osmo_g_fsms, list)
141 vty_out_fsm(vty, fsm);
142
143 return CMD_SUCCESS;
144}
145
146DEFUN(show_fsm, show_fsm_cmd,
147 "show fsm NAME",
148 SH_FSM_STR
149 "Display information about a single named finite state machine\n")
150{
151 struct osmo_fsm *fsm;
152
153 fsm = osmo_fsm_find_by_name(argv[0]);
154 if (!fsm) {
155 vty_out(vty, "Error: FSM with name '%s' doesn't exist!%s",
156 argv[0], VTY_NEWLINE);
157 return CMD_WARNING;
158 }
159
160 vty_out_fsm(vty, fsm);
161
162 return CMD_SUCCESS;
163}
164
165DEFUN(show_fsm_insts, show_fsm_insts_cmd,
166 "show fsm-instances all",
167 SH_FSMI_STR
168 "Display a list of all FSM instances of all finite state machine")
169{
170 struct osmo_fsm *fsm;
171
172 llist_for_each_entry(fsm, &osmo_g_fsms, list) {
173 struct osmo_fsm_inst *fsmi;
174 llist_for_each_entry(fsmi, &fsm->instances, list)
175 vty_out_fsm_inst(vty, fsmi);
176 }
177
178 return CMD_SUCCESS;
179}
180
181DEFUN(show_fsm_inst, show_fsm_inst_cmd,
182 "show fsm-instances NAME",
183 SH_FSMI_STR
184 "Display a list of all FSM instances of the named finite state machine")
185{
186 struct osmo_fsm *fsm;
187 struct osmo_fsm_inst *fsmi;
188
189 fsm = osmo_fsm_find_by_name(argv[0]);
190 if (!fsm) {
191 vty_out(vty, "Error: FSM with name '%s' doesn't exist!%s",
192 argv[0], VTY_NEWLINE);
193 return CMD_WARNING;
194 }
195
196 llist_for_each_entry(fsmi, &fsm->instances, list)
197 vty_out_fsm_inst(vty, fsmi);
198
199 return CMD_SUCCESS;
200}
201
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200202/*! Install VTY commands for FSM introspection
Harald Welte34193912017-01-07 11:49:55 +0100203 * This installs a couple of VTY commands for introspection of FSM
204 * classes as well as FSM instances. Call this once from your
205 * application if you want to support those commands. */
206void osmo_fsm_vty_add_cmds(void)
207{
Stefan Sperling218c4de2018-02-22 18:16:29 +0100208 static bool osmo_fsm_vty_cmds_installed;
209
210 /* Make sure FSM commands get installed only once.
211 * We might be called from libraries or from an application.
212 * An application might be oblivious to the fact that one or
213 * more of its libaries are using osmo_fsm. And likewise,
214 * any given library will not know if another library has
215 * already installled these commands. */
216 if (osmo_fsm_vty_cmds_installed)
217 return;
218
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +0700219 install_lib_element_ve(&show_fsm_cmd);
220 install_lib_element_ve(&show_fsms_cmd);
221 install_lib_element_ve(&show_fsm_inst_cmd);
222 install_lib_element_ve(&show_fsm_insts_cmd);
Stefan Sperling218c4de2018-02-22 18:16:29 +0100223 osmo_fsm_vty_cmds_installed = true;
Harald Welte34193912017-01-07 11:49:55 +0100224}