blob: 19c35daa1e1b0208dbab95692a59e5cd0bef8d23 [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 *
Harald Welte34193912017-01-07 11:49:55 +010017 */
18
19#include <stdlib.h>
20#include <string.h>
21
Pau Espin Pedrol88955fb2023-01-18 18:54:00 +010022#include "config.h"
Harald Welte34193912017-01-07 11:49:55 +010023
24#include <osmocom/vty/command.h>
25#include <osmocom/vty/buffer.h>
26#include <osmocom/vty/vty.h>
27#include <osmocom/vty/telnet_interface.h>
28#include <osmocom/vty/misc.h>
29
30#include <osmocom/core/fsm.h>
31#include <osmocom/core/logging.h>
32#include <osmocom/core/linuxlist.h>
33
Harald Welte8c648252017-10-16 15:17:03 +020034/*! \file fsm_vty.c
35 * Osmocom FSM introspection via VTY.
Harald Welte96e2a002017-06-12 21:44:18 +020036 *
37 * This is code implementing generic VTY access to Osmocom FSMs from
38 * libosmocore. This means that any application can expose all state
39 * of all instances of all registered FSM classes by calling a single
40 * command during startup: \ref osmo_fsm_vty_add_cmds
41 */
42
Harald Welte34193912017-01-07 11:49:55 +010043/* we don't want to add this to a public header file; this is simply
44 * exported by libosmocore and used by libmsomvty but not for public
45 * consumption. */
46extern struct llist_head osmo_g_fsms;
47
Neels Hofmeyr87e45502017-06-20 00:17:59 +020048/*! Print information about a FSM [class] to the given VTY
Harald Welte34193912017-01-07 11:49:55 +010049 * \param vty The VTY to which to print
Harald Weltecec4bbe2021-01-19 20:55:00 +010050 * \param[in] prefix prefix to print at start of each line (typically indenting)
Harald Welte34193912017-01-07 11:49:55 +010051 * \param[in] fsm The FSM class to print
52 */
Harald Weltecec4bbe2021-01-19 20:55:00 +010053void vty_out_fsm2(struct vty *vty, const char *prefix, struct osmo_fsm *fsm)
Harald Welte34193912017-01-07 11:49:55 +010054{
55 unsigned int i;
56 const struct value_string *evt_name;
57
Harald Weltecec4bbe2021-01-19 20:55:00 +010058 vty_out(vty, "%sFSM Name: '%s', Log Subsys: '%s'%s", prefix, fsm->name,
Harald Welte34193912017-01-07 11:49:55 +010059 log_category_name(fsm->log_subsys), VTY_NEWLINE);
60 /* list the events */
Stefan Sperlingcc817222018-02-26 19:02:30 +010061 if (fsm->event_names) {
62 for (evt_name = fsm->event_names; evt_name->str != NULL; evt_name++) {
Harald Weltecec4bbe2021-01-19 20:55:00 +010063 vty_out(vty, "%s Event %02u (0x%08x): '%s'%s", prefix, evt_name->value,
Harald Welteb17cc802022-05-16 22:14:48 +020064 (1U << evt_name->value), evt_name->str, VTY_NEWLINE);
Stefan Sperlingcc817222018-02-26 19:02:30 +010065 }
66 } else
Harald Weltecec4bbe2021-01-19 20:55:00 +010067 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 +010068
Harald Welte34193912017-01-07 11:49:55 +010069 /* list the states */
Harald Weltecec4bbe2021-01-19 20:55:00 +010070 vty_out(vty, "%s Number of States: %u%s", prefix, fsm->num_states, VTY_NEWLINE);
Harald Welte34193912017-01-07 11:49:55 +010071 for (i = 0; i < fsm->num_states; i++) {
72 const struct osmo_fsm_state *state = &fsm->states[i];
Harald Weltecec4bbe2021-01-19 20:55:00 +010073 vty_out(vty, "%s State %-20s InEvtMask: 0x%08x, OutStateMask: 0x%08x%s", prefix,
Harald Welte34193912017-01-07 11:49:55 +010074 state->name, state->in_event_mask, state->out_state_mask,
75 VTY_NEWLINE);
76 }
77}
78
Harald Weltecec4bbe2021-01-19 20:55:00 +010079/*! Print information about a FSM [class] to the given VTY
80 * \param vty The VTY to which to print
81 * \param[in] fsm The FSM class to print
82 */
83void vty_out_fsm(struct vty *vty, struct osmo_fsm *fsm)
84{
85 vty_out_fsm2(vty, "", fsm);
86}
87
88/*! Print a FSM instance to the given VTY
89 * \param vty The VTY to which to print
90 * \param[in] prefix prefix to print at start of each line (typically indenting)
91 * \param[in] fsmi The FSM instance to print
92 */
93void vty_out_fsm_inst2(struct vty *vty, const char *prefix, struct osmo_fsm_inst *fsmi)
94{
95 struct osmo_fsm_inst *child;
96
97 vty_out(vty, "%sFSM Instance Name: '%s', ID: '%s'%s", prefix,
98 fsmi->name, fsmi->id, VTY_NEWLINE);
99 vty_out(vty, "%s Log-Level: '%s', State: '%s'%s", prefix,
100 log_level_str(fsmi->log_level),
101 osmo_fsm_state_name(fsmi->fsm, fsmi->state),
102 VTY_NEWLINE);
103 if (fsmi->T)
104 vty_out(vty, "%s Timer: %u%s", prefix, fsmi->T, VTY_NEWLINE);
105 if (fsmi->proc.parent) {
106 vty_out(vty, "%s Parent: '%s', Term-Event: '%s'%s", prefix,
107 fsmi->proc.parent->name,
108 osmo_fsm_event_name(fsmi->proc.parent->fsm,
109 fsmi->proc.parent_term_event),
110 VTY_NEWLINE);
111 }
112 llist_for_each_entry(child, &fsmi->proc.children, proc.child) {
113 vty_out(vty, "%s Child: '%s'%s", prefix, child->name, VTY_NEWLINE);
114 }
115}
116
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200117/*! Print a FSM instance to the given VTY
Harald Welte34193912017-01-07 11:49:55 +0100118 * \param vty The VTY to which to print
119 * \param[in] fsmi The FSM instance to print
120 */
121void vty_out_fsm_inst(struct vty *vty, struct osmo_fsm_inst *fsmi)
122{
Harald Weltecec4bbe2021-01-19 20:55:00 +0100123 vty_out_fsm_inst2(vty, "", fsmi);
Harald Welte34193912017-01-07 11:49:55 +0100124}
125
126#define SH_FSM_STR SHOW_STR "Show information about finite state machines\n"
127#define SH_FSMI_STR SHOW_STR "Show information about finite state machine instances\n"
128
129DEFUN(show_fsms, show_fsms_cmd,
130 "show fsm all",
131 SH_FSM_STR
132 "Display a list of all registered finite state machines\n")
133{
134 struct osmo_fsm *fsm;
135
136 llist_for_each_entry(fsm, &osmo_g_fsms, list)
137 vty_out_fsm(vty, fsm);
138
139 return CMD_SUCCESS;
140}
141
142DEFUN(show_fsm, show_fsm_cmd,
143 "show fsm NAME",
144 SH_FSM_STR
145 "Display information about a single named finite state machine\n")
146{
147 struct osmo_fsm *fsm;
148
149 fsm = osmo_fsm_find_by_name(argv[0]);
150 if (!fsm) {
151 vty_out(vty, "Error: FSM with name '%s' doesn't exist!%s",
152 argv[0], VTY_NEWLINE);
153 return CMD_WARNING;
154 }
155
156 vty_out_fsm(vty, fsm);
157
158 return CMD_SUCCESS;
159}
160
Vadim Yanitskiyfb8cd652024-05-07 17:40:20 +0200161DEFUN(show_fsm_state_graph, show_fsm_state_graph_cmd,
162 "show fsm-state-graph NAME",
163 SHOW_STR "Generate a state transition graph (using DOT language)\n"
164 "FSM name\n")
165{
166 const struct osmo_fsm *fsm;
167
168 fsm = osmo_fsm_find_by_name(argv[0]);
169 if (!fsm) {
170 vty_out(vty, "Error: FSM with name '%s' doesn't exist!%s",
171 argv[0], VTY_NEWLINE);
172 return CMD_WARNING;
173 }
174
175 vty_out(vty, "digraph \"%s\" {%s", fsm->name, VTY_NEWLINE);
176
177 for (unsigned int i = 0; i < fsm->num_states; i++) {
178 const struct osmo_fsm_state *st = &fsm->states[i];
179
180 vty_out(vty, "\t\"%s\"; # out_state_mask=0x%08x%s",
181 st->name, st->out_state_mask, VTY_NEWLINE);
182
183 for (unsigned int j = 0; j < sizeof(st->out_state_mask) * 8; j++) {
184 if (~st->out_state_mask & (1 << j))
185 continue;
186 vty_out(vty, "\t\"%s\" -> \"%s\";%s",
187 st->name, osmo_fsm_state_name(fsm, j),
188 VTY_NEWLINE);
189 }
190
191 vty_out(vty, "%s", VTY_NEWLINE);
192 }
193
194 vty_out(vty, "}%s", VTY_NEWLINE);
195
196 return CMD_SUCCESS;
197}
198
Harald Welte34193912017-01-07 11:49:55 +0100199DEFUN(show_fsm_insts, show_fsm_insts_cmd,
200 "show fsm-instances all",
201 SH_FSMI_STR
202 "Display a list of all FSM instances of all finite state machine")
203{
204 struct osmo_fsm *fsm;
205
206 llist_for_each_entry(fsm, &osmo_g_fsms, list) {
207 struct osmo_fsm_inst *fsmi;
208 llist_for_each_entry(fsmi, &fsm->instances, list)
209 vty_out_fsm_inst(vty, fsmi);
210 }
211
212 return CMD_SUCCESS;
213}
214
215DEFUN(show_fsm_inst, show_fsm_inst_cmd,
216 "show fsm-instances NAME",
217 SH_FSMI_STR
218 "Display a list of all FSM instances of the named finite state machine")
219{
220 struct osmo_fsm *fsm;
221 struct osmo_fsm_inst *fsmi;
222
223 fsm = osmo_fsm_find_by_name(argv[0]);
224 if (!fsm) {
225 vty_out(vty, "Error: FSM with name '%s' doesn't exist!%s",
226 argv[0], VTY_NEWLINE);
227 return CMD_WARNING;
228 }
229
230 llist_for_each_entry(fsmi, &fsm->instances, list)
231 vty_out_fsm_inst(vty, fsmi);
232
233 return CMD_SUCCESS;
234}
235
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200236/*! Install VTY commands for FSM introspection
Harald Welte34193912017-01-07 11:49:55 +0100237 * This installs a couple of VTY commands for introspection of FSM
238 * classes as well as FSM instances. Call this once from your
239 * application if you want to support those commands. */
240void osmo_fsm_vty_add_cmds(void)
241{
Stefan Sperling218c4de2018-02-22 18:16:29 +0100242 static bool osmo_fsm_vty_cmds_installed;
243
244 /* Make sure FSM commands get installed only once.
245 * We might be called from libraries or from an application.
246 * An application might be oblivious to the fact that one or
247 * more of its libaries are using osmo_fsm. And likewise,
248 * any given library will not know if another library has
249 * already installled these commands. */
250 if (osmo_fsm_vty_cmds_installed)
251 return;
252
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +0700253 install_lib_element_ve(&show_fsm_cmd);
254 install_lib_element_ve(&show_fsms_cmd);
Vadim Yanitskiyfb8cd652024-05-07 17:40:20 +0200255 install_lib_element_ve(&show_fsm_state_graph_cmd);
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +0700256 install_lib_element_ve(&show_fsm_inst_cmd);
257 install_lib_element_ve(&show_fsm_insts_cmd);
Stefan Sperling218c4de2018-02-22 18:16:29 +0100258 osmo_fsm_vty_cmds_installed = true;
Harald Welte34193912017-01-07 11:49:55 +0100259}