blob: 6e3ee3750e7844564f55738c74b2ba7bf24078e5 [file] [log] [blame]
Harald Welte34b5a952019-05-27 11:54:11 +02001/* Osmocom VTY interface functions in TTCN-3
2 * (C) 2017-2018 Harald Welte <laforge@gnumonks.org>
3 * contributions by sysmocom - s.f.m.c. GmbH
4 * All rights reserved.
5 *
6 * Released under the terms of GNU General Public License, Version 2 or
7 * (at your option) any later version.
8 *
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 */
11
Harald Welte8542cef2017-07-19 20:06:26 +020012module Osmocom_VTY_Functions {
Pau Espin Pedrol3bc82b42021-02-05 16:01:36 +010013
14 import from Misc_Helpers all;
Harald Welte8542cef2017-07-19 20:06:26 +020015 import from TELNETasp_PortType all;
Stefan Sperlingcff13562018-11-13 15:24:06 +010016 import from Osmocom_Types all;
Neels Hofmeyre23496a2021-12-13 17:07:40 +010017 import from TCCConversion_Functions all;
Harald Welte8542cef2017-07-19 20:06:26 +020018
Harald Welte553f6552018-01-24 18:50:53 +010019 modulepar {
20 charstring mp_prompt_prefix := "OpenBSC";
Vadim Yanitskiybc1e66a2021-01-30 14:14:15 +010021 float mp_prompt_timeout := 2.0;
Harald Welte553f6552018-01-24 18:50:53 +010022 }
Harald Welte8542cef2017-07-19 20:06:26 +020023
Harald Welte553f6552018-01-24 18:50:53 +010024 const charstring VTY_VIEW_SUFFIX := "> ";
25 const charstring VTY_ENABLE_SUFFIX := "# ";
26 const charstring VTY_CFG_SUFFIX := "(*)";
27
28 template charstring t_vty_unknown := pattern "*% Unknown command.";
Harald Welte8542cef2017-07-19 20:06:26 +020029
30 /* configure prompts in TELNETasp module */
Harald Weltea2663252018-09-10 10:21:44 +020031 function f_vty_set_prompts(TELNETasp_PT pt, charstring prompt_prefix := mp_prompt_prefix) {
Harald Welte553f6552018-01-24 18:50:53 +010032 var ASP_TelnetDynamicConfig vty_prompt[3] := {
33 {
34 prompt := {
35 id := 1,
Harald Weltea2663252018-09-10 10:21:44 +020036 prompt := prompt_prefix & VTY_VIEW_SUFFIX,
Harald Welte553f6552018-01-24 18:50:53 +010037 has_wildcards := false
38 }
39 }, {
40 prompt := {
41 id := 2,
Harald Weltea2663252018-09-10 10:21:44 +020042 prompt := prompt_prefix & VTY_ENABLE_SUFFIX,
Harald Welte553f6552018-01-24 18:50:53 +010043 has_wildcards := false
44 }
45 }, {
46 prompt := {
47 id := 3,
Harald Weltea2663252018-09-10 10:21:44 +020048 prompt := prompt_prefix & VTY_CFG_SUFFIX,
Harald Welte553f6552018-01-24 18:50:53 +010049 has_wildcards := true
50 }
51 }
52 };
53
Harald Welte8542cef2017-07-19 20:06:26 +020054 /* set some configuration that isn't possible to express
55 * in the config file due to syntactic restrictions (Who invents config
56 * files that don't permit regular expressions? */
57 for (var integer i := 0; i < sizeof(vty_prompt); i:= i + 1) {
Harald Welte553f6552018-01-24 18:50:53 +010058 pt.send(vty_prompt[i]);
Harald Welte8542cef2017-07-19 20:06:26 +020059 }
60 }
61
62 /* wait for any of the permitted prompts; buffer + return all intermediate output */
Vadim Yanitskiy26e30aa2021-01-30 14:06:37 +010063 function f_vty_wait_for_prompt(TELNETasp_PT pt, boolean strict := true, charstring log_label := "(?)")
64 return charstring {
Harald Welte8542cef2017-07-19 20:06:26 +020065 var charstring rx, buf := "";
Stefan Sperling23b45972018-07-27 17:20:38 +020066 var integer fd;
Vadim Yanitskiybc1e66a2021-01-30 14:14:15 +010067 timer T;
Harald Welte8542cef2017-07-19 20:06:26 +020068
Vadim Yanitskiybc1e66a2021-01-30 14:14:15 +010069 T.start(mp_prompt_timeout);
Harald Welte8542cef2017-07-19 20:06:26 +020070 alt {
Vadim Yanitskiy26e30aa2021-01-30 14:06:37 +010071 [] pt.receive(pattern "[\w-]+" & VTY_VIEW_SUFFIX) { };
72 [] pt.receive(pattern "[\w-]+\# ") { };
73 [] pt.receive(pattern "[\w-]+\(*\)\# ") { };
74 [] pt.receive(t_vty_unknown) -> value rx {
75 if (strict) {
76 setverdict(fail, "VTY: Unknown Command: " & log_label);
Daniel Willmanne4ff5372018-07-05 17:35:03 +020077 mtc.stop;
Vadim Yanitskiy26e30aa2021-01-30 14:06:37 +010078 } else {
79 log("VTY: Unknown Command (ignored): " & log_label);
80 buf := buf & rx;
81 repeat;
82 }
83 };
84 [] pt.receive(charstring:?) -> value rx { buf := buf & rx; repeat };
85 [] pt.receive(integer:?) -> value fd {
86 if (fd == -1) {
87 setverdict(fail, "VTY Telnet Connection Failure: " & log_label);
88 mtc.stop;
89 } else {
90 repeat; /* telnet connection succeeded */
91 }
92 }
93 [] T.timeout {
94 setverdict(fail, "VTY Timeout for prompt: " & log_label);
95 mtc.stop;
96 };
Harald Welte8542cef2017-07-19 20:06:26 +020097 }
98 T.stop;
99 return buf;
100 }
101
102 /* send a VTY command and obtain response until prompt is received */
Neels Hofmeyr2fe5ad12020-08-09 21:50:25 +0000103 function f_vty_transceive_ret(TELNETasp_PT pt, charstring tx, boolean strict := true) return charstring {
Harald Welte8542cef2017-07-19 20:06:26 +0200104 pt.send(tx);
Neels Hofmeyr9ebabc82020-11-25 22:56:13 +0000105 return f_vty_wait_for_prompt(pt, strict, tx);
Harald Welte8542cef2017-07-19 20:06:26 +0200106 }
107
108 /* send a VTY command and obtain response until prompt is received */
Neels Hofmeyr2fe5ad12020-08-09 21:50:25 +0000109 function f_vty_transceive(TELNETasp_PT pt, charstring tx, boolean strict := true) {
110 var charstring unused := f_vty_transceive_ret(pt, tx, strict);
Harald Welte8542cef2017-07-19 20:06:26 +0200111 }
112
113 type integer BtsNr (0..255);
114 type integer BtsTrxNr (0..255);
115 type integer BtsTimeslotNr (0..7);
Philipp Maierd0e64b02019-03-13 14:15:23 +0100116 type integer MscNr (0..255);
Pau Espin Pedrolc675b612020-01-09 19:55:40 +0100117 type integer Cs7Nr (0..255);
Harald Welte8542cef2017-07-19 20:06:26 +0200118
119 type charstring BtsGprsMode ("none", "gprs", "egrps");
120
121 /* enter the'confiugration' mode of the VTY */
122 function f_vty_enter_config(TELNETasp_PT pt) {
123 f_vty_transceive(pt, "configure terminal")
124 }
125
126 function f_vty_enter_cfg_network(TELNETasp_PT pt) {
127 f_vty_enter_config(pt);
128 f_vty_transceive(pt, "network")
129 }
130
131 function f_vty_enter_cfg_bts(TELNETasp_PT pt, BtsNr bts := 0) {
132 f_vty_enter_cfg_network(pt);
133 f_vty_transceive(pt, "bts " & int2str(bts));
134 }
135
136 function f_vty_enter_cfg_trx(TELNETasp_PT pt, BtsNr bts := 0, BtsTrxNr trx := 0) {
137 f_vty_enter_cfg_bts(pt, bts);
138 f_vty_transceive(pt, "trx " & int2str(trx));
139 }
140
141 function f_vty_enter_cfg_ts(TELNETasp_PT pt, BtsNr bts := 0, BtsTrxNr trx := 0, BtsTimeslotNr ts) {
142 f_vty_enter_cfg_trx(pt, bts, trx);
143 f_vty_transceive(pt, "timeslot " & int2str(ts));
144 }
145
Philipp Maierd0e64b02019-03-13 14:15:23 +0100146 function f_vty_enter_cfg_msc(TELNETasp_PT pt, MscNr msc := 0) {
147 f_vty_enter_config(pt);
148 f_vty_transceive(pt, "msc " & int2str(msc));
149 }
150
Pau Espin Pedrolc675b612020-01-09 19:55:40 +0100151 function f_vty_enter_cfg_cs7_inst(TELNETasp_PT pt, Cs7Nr cs7_inst := 0) {
152 f_vty_enter_config(pt);
153 f_vty_transceive(pt, "cs7 instance " & int2str(cs7_inst));
154 }
155
Harald Weltef640a012018-04-14 17:49:21 +0200156type record of charstring rof_charstring;
Neels Hofmeyr1a1f8542020-11-25 23:39:46 +0000157function f_vty_config3(TELNETasp_PT pt, rof_charstring config_nodes, rof_charstring cmds)
Harald Welte872ce172018-02-16 22:10:33 +0100158{
159 /* enter config mode; enter node */
160 f_vty_enter_config(pt);
Harald Weltef640a012018-04-14 17:49:21 +0200161 for (var integer i := 0; i < sizeof(config_nodes); i := i+1) {
162 f_vty_transceive(pt, config_nodes[i]);
163 }
Neels Hofmeyr1a1f8542020-11-25 23:39:46 +0000164 /* execute commands */
165 for (var integer i := 0; i < sizeof(cmds); i := i+1) {
166 f_vty_transceive(pt, cmds[i]);
167 }
Harald Welte872ce172018-02-16 22:10:33 +0100168 /* leave config mode */
169 f_vty_transceive(pt, "end");
170}
171
Neels Hofmeyr1a1f8542020-11-25 23:39:46 +0000172function f_vty_config2(TELNETasp_PT pt, rof_charstring config_nodes, charstring cmd)
173{
174 f_vty_config3(pt, config_nodes, { cmd });
175}
Harald Welte872ce172018-02-16 22:10:33 +0100176
Harald Weltef640a012018-04-14 17:49:21 +0200177function f_vty_config(TELNETasp_PT pt, charstring config_node, charstring cmd)
178{
179 f_vty_config2(pt, {config_node}, cmd);
180}
181
Neels Hofmeyr2a5670b2020-11-25 23:39:57 +0000182function f_vty_cfg_bts(TELNETasp_PT pt, BtsNr bts := 0, rof_charstring cmds) {
183 f_vty_config3(pt, {"network", "bts " & int2str(bts)}, cmds);
184}
185
186function f_vty_cfg_msc(TELNETasp_PT pt, MscNr msc := 0, rof_charstring cmds) {
187 f_vty_config3(pt, {"msc " & int2str(msc)}, cmds);
188}
189
Alexander Couzens98aa59e2018-06-12 13:45:59 +0200190function f_vty_transceive_match(TELNETasp_PT pt, charstring cmd, template charstring exp_ret) {
191 var charstring ret := f_vty_transceive_ret(pt, cmd);
192 if (not match(ret, exp_ret)) {
193 setverdict(fail, "Non-matching VTY response: ", ret);
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200194 mtc.stop;
Alexander Couzens98aa59e2018-06-12 13:45:59 +0200195 }
196}
197
Alexander Couzens1e6d9902018-06-12 13:48:26 +0200198function f_vty_transceive_not_match(TELNETasp_PT pt, charstring cmd, template charstring exp_ret) {
199 var charstring ret := f_vty_transceive_ret(pt, cmd);
200 if (match(ret, exp_ret)) {
201 setverdict(fail, "Unexpected matching VTY response: ", ret);
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200202 mtc.stop;
Alexander Couzens1e6d9902018-06-12 13:48:26 +0200203 }
204}
205
Stefan Sperlingcff13562018-11-13 15:24:06 +0100206function f_vty_transceive_match_regex(TELNETasp_PT pt, charstring cmd, charstring regex, integer groupno) return charstring
207{
208 var charstring resp := f_vty_transceive_ret(pt, cmd);
209 return regexp(resp, regex, groupno);
210}
211
212function f_vty_transceive_match_regexp_retry(TELNETasp_PT pt, charstring cmd, charstring regex,
213 integer groupno, integer num_attempts, float retry_delay) return charstring
214{
215 while (num_attempts > 0) {
216 var charstring ret := f_vty_transceive_match_regex(pt, cmd, regex, groupno);
217 if (ret != "") {
218 return ret;
219 }
220 f_sleep(retry_delay);
221 num_attempts := num_attempts - 1;
222 }
223
Pau Espin Pedrol3bc82b42021-02-05 16:01:36 +0100224 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
225 log2str("No matching VTY response for regular expression '",
226 regex, "' after ", num_attempts, " attempts." ));
227 return "";
Stefan Sperlingcff13562018-11-13 15:24:06 +0100228}
Harald Weltef640a012018-04-14 17:49:21 +0200229
Neels Hofmeyre23496a2021-12-13 17:07:40 +0100230/* Return a count of how many times sub_str occurs in str. */
231function f_strstr_count(in charstring str, in charstring sub_str) return integer
232{
233 var integer count := 0;
234 var integer pos := 0;
235
236 while (true) {
237 var integer at := f_strstr(str, sub_str, pos);
238 if (at < 0) {
239 break;
240 }
241 count := count + 1;
242 pos := at + 1;
243 }
244 return count;
245}
246
247private type record of charstring StrList;
248
249/* Perform a 'show talloc-context' to get a count of the given object_strs that are still allocated.
250 * Retry 'attempts' times until the actual talloc object count matches 'expect_count'.
251 * Useful to ensure that no mem leaks remain after running a test. */
252function f_verify_talloc_count(TELNETasp_PT pt, StrList object_strs, integer expect_count := 0,
253 integer attempts := 5, float wait_time := 3.0)
254{
255 var charstring show_cmd := "show talloc-context application full filter ";
256 for (var integer i := 0; i < lengthof(object_strs); i := i + 1) {
257 var charstring obj_str := object_strs[i];
258 /* spaces confuse the VTY command */
259 obj_str := f_replaceEveryOccurenceOfSubstring(obj_str, " ", ".");
260 /* In the regexp, expect word start and word end to bound the obj name */
261 obj_str := "\\<" & obj_str & "\\>";
262 if (i > 0) {
263 show_cmd := show_cmd & "\\|";
264 }
265 show_cmd := show_cmd & obj_str;
266 }
267
268 while (attempts > 0) {
269 attempts := attempts - 1;
270 var charstring ret := f_vty_transceive_ret(pt, show_cmd);
271
272 var boolean ok := true;
273 for (var integer i := 0; i < lengthof(object_strs); i := i + 1) {
274 var charstring object_str := object_strs[i];
275 var integer count := f_strstr_count(ret, object_str);
276 log("talloc reports ", object_str, " x ", count, ", expecting ", expect_count);
277 if (count != expect_count) {
278 ok := false;
279 }
280 }
281 if (ok) {
282 return;
283 }
284 if (attempts == 0) {
285 break;
286 }
287 log("count mismatch, retrying in ", wait_time);
288 f_sleep(wait_time);
289 }
Neels Hofmeyrc0633b72023-04-15 17:58:07 +0200290 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "talloc count mismatch");
Neels Hofmeyre23496a2021-12-13 17:07:40 +0100291}
292
Harald Welte8542cef2017-07-19 20:06:26 +0200293}