blob: b982a8ffb44530d61fc693dd0bd3498931678564 [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;
Neels Hofmeyr11ac91c2023-06-10 01:09:04 +020018 import from Socket_API_Definitions all;
Harald Welte8542cef2017-07-19 20:06:26 +020019
Harald Welte553f6552018-01-24 18:50:53 +010020 modulepar {
21 charstring mp_prompt_prefix := "OpenBSC";
Vadim Yanitskiybc1e66a2021-01-30 14:14:15 +010022 float mp_prompt_timeout := 2.0;
Harald Welte553f6552018-01-24 18:50:53 +010023 }
Harald Welte8542cef2017-07-19 20:06:26 +020024
Harald Welte553f6552018-01-24 18:50:53 +010025 const charstring VTY_VIEW_SUFFIX := "> ";
26 const charstring VTY_ENABLE_SUFFIX := "# ";
27 const charstring VTY_CFG_SUFFIX := "(*)";
28
29 template charstring t_vty_unknown := pattern "*% Unknown command.";
Harald Welte8542cef2017-07-19 20:06:26 +020030
31 /* configure prompts in TELNETasp module */
Harald Weltea2663252018-09-10 10:21:44 +020032 function f_vty_set_prompts(TELNETasp_PT pt, charstring prompt_prefix := mp_prompt_prefix) {
Harald Welte553f6552018-01-24 18:50:53 +010033 var ASP_TelnetDynamicConfig vty_prompt[3] := {
34 {
35 prompt := {
36 id := 1,
Harald Weltea2663252018-09-10 10:21:44 +020037 prompt := prompt_prefix & VTY_VIEW_SUFFIX,
Harald Welte553f6552018-01-24 18:50:53 +010038 has_wildcards := false
39 }
40 }, {
41 prompt := {
42 id := 2,
Harald Weltea2663252018-09-10 10:21:44 +020043 prompt := prompt_prefix & VTY_ENABLE_SUFFIX,
Harald Welte553f6552018-01-24 18:50:53 +010044 has_wildcards := false
45 }
46 }, {
47 prompt := {
48 id := 3,
Harald Weltea2663252018-09-10 10:21:44 +020049 prompt := prompt_prefix & VTY_CFG_SUFFIX,
Harald Welte553f6552018-01-24 18:50:53 +010050 has_wildcards := true
51 }
52 }
53 };
54
Harald Welte8542cef2017-07-19 20:06:26 +020055 /* set some configuration that isn't possible to express
56 * in the config file due to syntactic restrictions (Who invents config
57 * files that don't permit regular expressions? */
58 for (var integer i := 0; i < sizeof(vty_prompt); i:= i + 1) {
Harald Welte553f6552018-01-24 18:50:53 +010059 pt.send(vty_prompt[i]);
Harald Welte8542cef2017-07-19 20:06:26 +020060 }
61 }
62
63 /* wait for any of the permitted prompts; buffer + return all intermediate output */
Vadim Yanitskiy26e30aa2021-01-30 14:06:37 +010064 function f_vty_wait_for_prompt(TELNETasp_PT pt, boolean strict := true, charstring log_label := "(?)")
65 return charstring {
Harald Welte8542cef2017-07-19 20:06:26 +020066 var charstring rx, buf := "";
Stefan Sperling23b45972018-07-27 17:20:38 +020067 var integer fd;
Vadim Yanitskiybc1e66a2021-01-30 14:14:15 +010068 timer T;
Harald Welte8542cef2017-07-19 20:06:26 +020069
Vadim Yanitskiybc1e66a2021-01-30 14:14:15 +010070 T.start(mp_prompt_timeout);
Harald Welte8542cef2017-07-19 20:06:26 +020071 alt {
Vadim Yanitskiy26e30aa2021-01-30 14:06:37 +010072 [] pt.receive(pattern "[\w-]+" & VTY_VIEW_SUFFIX) { };
73 [] pt.receive(pattern "[\w-]+\# ") { };
74 [] pt.receive(pattern "[\w-]+\(*\)\# ") { };
75 [] pt.receive(t_vty_unknown) -> value rx {
76 if (strict) {
77 setverdict(fail, "VTY: Unknown Command: " & log_label);
Daniel Willmanne4ff5372018-07-05 17:35:03 +020078 mtc.stop;
Vadim Yanitskiy26e30aa2021-01-30 14:06:37 +010079 } else {
80 log("VTY: Unknown Command (ignored): " & log_label);
81 buf := buf & rx;
82 repeat;
83 }
84 };
85 [] pt.receive(charstring:?) -> value rx { buf := buf & rx; repeat };
86 [] pt.receive(integer:?) -> value fd {
87 if (fd == -1) {
88 setverdict(fail, "VTY Telnet Connection Failure: " & log_label);
89 mtc.stop;
90 } else {
91 repeat; /* telnet connection succeeded */
92 }
93 }
94 [] T.timeout {
95 setverdict(fail, "VTY Timeout for prompt: " & log_label);
96 mtc.stop;
97 };
Harald Welte8542cef2017-07-19 20:06:26 +020098 }
99 T.stop;
100 return buf;
101 }
102
103 /* send a VTY command and obtain response until prompt is received */
Neels Hofmeyr2fe5ad12020-08-09 21:50:25 +0000104 function f_vty_transceive_ret(TELNETasp_PT pt, charstring tx, boolean strict := true) return charstring {
Harald Welte8542cef2017-07-19 20:06:26 +0200105 pt.send(tx);
Neels Hofmeyr9ebabc82020-11-25 22:56:13 +0000106 return f_vty_wait_for_prompt(pt, strict, tx);
Harald Welte8542cef2017-07-19 20:06:26 +0200107 }
108
109 /* send a VTY command and obtain response until prompt is received */
Neels Hofmeyr2fe5ad12020-08-09 21:50:25 +0000110 function f_vty_transceive(TELNETasp_PT pt, charstring tx, boolean strict := true) {
111 var charstring unused := f_vty_transceive_ret(pt, tx, strict);
Harald Welte8542cef2017-07-19 20:06:26 +0200112 }
113
114 type integer BtsNr (0..255);
115 type integer BtsTrxNr (0..255);
116 type integer BtsTimeslotNr (0..7);
Philipp Maierd0e64b02019-03-13 14:15:23 +0100117 type integer MscNr (0..255);
Pau Espin Pedrolc675b612020-01-09 19:55:40 +0100118 type integer Cs7Nr (0..255);
Harald Welte8542cef2017-07-19 20:06:26 +0200119
120 type charstring BtsGprsMode ("none", "gprs", "egrps");
121
122 /* enter the'confiugration' mode of the VTY */
123 function f_vty_enter_config(TELNETasp_PT pt) {
124 f_vty_transceive(pt, "configure terminal")
125 }
126
127 function f_vty_enter_cfg_network(TELNETasp_PT pt) {
128 f_vty_enter_config(pt);
129 f_vty_transceive(pt, "network")
130 }
131
132 function f_vty_enter_cfg_bts(TELNETasp_PT pt, BtsNr bts := 0) {
133 f_vty_enter_cfg_network(pt);
134 f_vty_transceive(pt, "bts " & int2str(bts));
135 }
136
137 function f_vty_enter_cfg_trx(TELNETasp_PT pt, BtsNr bts := 0, BtsTrxNr trx := 0) {
138 f_vty_enter_cfg_bts(pt, bts);
139 f_vty_transceive(pt, "trx " & int2str(trx));
140 }
141
142 function f_vty_enter_cfg_ts(TELNETasp_PT pt, BtsNr bts := 0, BtsTrxNr trx := 0, BtsTimeslotNr ts) {
143 f_vty_enter_cfg_trx(pt, bts, trx);
144 f_vty_transceive(pt, "timeslot " & int2str(ts));
145 }
146
Philipp Maierd0e64b02019-03-13 14:15:23 +0100147 function f_vty_enter_cfg_msc(TELNETasp_PT pt, MscNr msc := 0) {
148 f_vty_enter_config(pt);
149 f_vty_transceive(pt, "msc " & int2str(msc));
150 }
151
Pau Espin Pedrolc675b612020-01-09 19:55:40 +0100152 function f_vty_enter_cfg_cs7_inst(TELNETasp_PT pt, Cs7Nr cs7_inst := 0) {
153 f_vty_enter_config(pt);
154 f_vty_transceive(pt, "cs7 instance " & int2str(cs7_inst));
155 }
156
Harald Weltef640a012018-04-14 17:49:21 +0200157type record of charstring rof_charstring;
Neels Hofmeyr1a1f8542020-11-25 23:39:46 +0000158function f_vty_config3(TELNETasp_PT pt, rof_charstring config_nodes, rof_charstring cmds)
Harald Welte872ce172018-02-16 22:10:33 +0100159{
160 /* enter config mode; enter node */
161 f_vty_enter_config(pt);
Harald Weltef640a012018-04-14 17:49:21 +0200162 for (var integer i := 0; i < sizeof(config_nodes); i := i+1) {
163 f_vty_transceive(pt, config_nodes[i]);
164 }
Neels Hofmeyr1a1f8542020-11-25 23:39:46 +0000165 /* execute commands */
166 for (var integer i := 0; i < sizeof(cmds); i := i+1) {
167 f_vty_transceive(pt, cmds[i]);
168 }
Harald Welte872ce172018-02-16 22:10:33 +0100169 /* leave config mode */
170 f_vty_transceive(pt, "end");
171}
172
Neels Hofmeyr1a1f8542020-11-25 23:39:46 +0000173function f_vty_config2(TELNETasp_PT pt, rof_charstring config_nodes, charstring cmd)
174{
175 f_vty_config3(pt, config_nodes, { cmd });
176}
Harald Welte872ce172018-02-16 22:10:33 +0100177
Harald Weltef640a012018-04-14 17:49:21 +0200178function f_vty_config(TELNETasp_PT pt, charstring config_node, charstring cmd)
179{
180 f_vty_config2(pt, {config_node}, cmd);
181}
182
Neels Hofmeyr2a5670b2020-11-25 23:39:57 +0000183function f_vty_cfg_bts(TELNETasp_PT pt, BtsNr bts := 0, rof_charstring cmds) {
184 f_vty_config3(pt, {"network", "bts " & int2str(bts)}, cmds);
185}
186
187function f_vty_cfg_msc(TELNETasp_PT pt, MscNr msc := 0, rof_charstring cmds) {
188 f_vty_config3(pt, {"msc " & int2str(msc)}, cmds);
189}
190
Alexander Couzens98aa59e2018-06-12 13:45:59 +0200191function f_vty_transceive_match(TELNETasp_PT pt, charstring cmd, template charstring exp_ret) {
192 var charstring ret := f_vty_transceive_ret(pt, cmd);
193 if (not match(ret, exp_ret)) {
194 setverdict(fail, "Non-matching VTY response: ", ret);
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200195 mtc.stop;
Alexander Couzens98aa59e2018-06-12 13:45:59 +0200196 }
197}
198
Alexander Couzens1e6d9902018-06-12 13:48:26 +0200199function f_vty_transceive_not_match(TELNETasp_PT pt, charstring cmd, template charstring exp_ret) {
200 var charstring ret := f_vty_transceive_ret(pt, cmd);
201 if (match(ret, exp_ret)) {
202 setverdict(fail, "Unexpected matching VTY response: ", ret);
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200203 mtc.stop;
Alexander Couzens1e6d9902018-06-12 13:48:26 +0200204 }
205}
206
Stefan Sperlingcff13562018-11-13 15:24:06 +0100207function f_vty_transceive_match_regex(TELNETasp_PT pt, charstring cmd, charstring regex, integer groupno) return charstring
208{
209 var charstring resp := f_vty_transceive_ret(pt, cmd);
210 return regexp(resp, regex, groupno);
211}
212
213function f_vty_transceive_match_regexp_retry(TELNETasp_PT pt, charstring cmd, charstring regex,
214 integer groupno, integer num_attempts, float retry_delay) return charstring
215{
216 while (num_attempts > 0) {
217 var charstring ret := f_vty_transceive_match_regex(pt, cmd, regex, groupno);
218 if (ret != "") {
219 return ret;
220 }
221 f_sleep(retry_delay);
222 num_attempts := num_attempts - 1;
223 }
224
Pau Espin Pedrol3bc82b42021-02-05 16:01:36 +0100225 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
226 log2str("No matching VTY response for regular expression '",
227 regex, "' after ", num_attempts, " attempts." ));
228 return "";
Stefan Sperlingcff13562018-11-13 15:24:06 +0100229}
Harald Weltef640a012018-04-14 17:49:21 +0200230
Neels Hofmeyre23496a2021-12-13 17:07:40 +0100231private type record of charstring StrList;
232
233/* Perform a 'show talloc-context' to get a count of the given object_strs that are still allocated.
234 * Retry 'attempts' times until the actual talloc object count matches 'expect_count'.
235 * Useful to ensure that no mem leaks remain after running a test. */
236function f_verify_talloc_count(TELNETasp_PT pt, StrList object_strs, integer expect_count := 0,
237 integer attempts := 5, float wait_time := 3.0)
238{
239 var charstring show_cmd := "show talloc-context application full filter ";
240 for (var integer i := 0; i < lengthof(object_strs); i := i + 1) {
241 var charstring obj_str := object_strs[i];
242 /* spaces confuse the VTY command */
243 obj_str := f_replaceEveryOccurenceOfSubstring(obj_str, " ", ".");
244 /* In the regexp, expect word start and word end to bound the obj name */
245 obj_str := "\\<" & obj_str & "\\>";
246 if (i > 0) {
247 show_cmd := show_cmd & "\\|";
248 }
249 show_cmd := show_cmd & obj_str;
250 }
251
252 while (attempts > 0) {
253 attempts := attempts - 1;
254 var charstring ret := f_vty_transceive_ret(pt, show_cmd);
255
256 var boolean ok := true;
257 for (var integer i := 0; i < lengthof(object_strs); i := i + 1) {
258 var charstring object_str := object_strs[i];
259 var integer count := f_strstr_count(ret, object_str);
260 log("talloc reports ", object_str, " x ", count, ", expecting ", expect_count);
261 if (count != expect_count) {
262 ok := false;
263 }
264 }
265 if (ok) {
266 return;
267 }
268 if (attempts == 0) {
269 break;
270 }
271 log("count mismatch, retrying in ", wait_time);
272 f_sleep(wait_time);
273 }
Neels Hofmeyrc0633b72023-04-15 17:58:07 +0200274 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "talloc count mismatch");
Neels Hofmeyre23496a2021-12-13 17:07:40 +0100275}
276
Pau Espin Pedrol601b5cd2024-04-17 19:16:17 +0200277public function f_verify_talloc_bytes(TELNETasp_PT pt, Misc_Helpers.ro_charstring object_strs, integer expect_bytes := 0,
Neels Hofmeyr75d905b2023-04-27 00:30:25 +0200278 integer attempts := 5, float wait_time := 3.0)
279{
280 var charstring show_cmd := "show talloc-context application brief";
281
282 while (attempts > 0) {
283 attempts := attempts - 1;
284 var charstring ret := f_vty_transceive_ret(pt, show_cmd);
285
Pau Espin Pedrol601b5cd2024-04-17 19:16:17 +0200286 var Misc_Helpers.ro_charstring lines := f_str_split(ret);
Neels Hofmeyr75d905b2023-04-27 00:30:25 +0200287
288 var boolean ok := true;
289 for (var integer i := 0; i < lengthof(object_strs); i := i + 1) {
290 var charstring object_str := object_strs[i];
291
292 var integer bytes := 0;
293
294 for (var integer j := 0; j < lengthof(lines); j := j + 1) {
295 var charstring line := lines[j];
296 if (f_strstr(line, object_str) < 0) {
297 continue;
298 }
Pau Espin Pedrol601b5cd2024-04-17 19:16:17 +0200299 var Misc_Helpers.ro_charstring tokens := f_str_split(line, " ");
Neels Hofmeyr75d905b2023-04-27 00:30:25 +0200300 if (lengthof(tokens) < 4) {
301 continue;
302 }
303 if (tokens[3] != "bytes") {
304 continue;
305 }
306 bytes := f_str2int(tokens[2]);
307 }
308
309 if (bytes != expect_bytes) {
310 ok := false;
311 log("ERROR: talloc reports ", object_str, " = ", bytes, " bytes, expecting ", expect_bytes,
312 " from VTY response ", lines);
313 } else {
314 log("ok: talloc reports ", object_str, " = ", bytes, " bytes");
315 }
316 }
317 if (ok) {
318 return;
319 }
320 if (attempts == 0) {
321 break;
322 }
323 log("bytes count mismatch, retrying in ", wait_time);
324 f_sleep(wait_time);
325 }
326 setverdict(fail, "talloc bytes count mismatch");
327 mtc.stop;
328}
329
Oliver Smith7bb63cf2023-10-20 13:54:28 +0200330public function f_logp(TELNETasp_PT pt, charstring log_msg)
331{
332 // log on TTCN3 log output
333 log(log_msg);
334 // log in stderr log
335 if (pt.checkstate("Mapped")) {
336 f_vty_transceive(pt, "logp lglobal notice TTCN3 f_logp(): " & log_msg);
337 }
338}
339
Harald Welte8542cef2017-07-19 20:06:26 +0200340}