230 lines
6.7 KiB
Plaintext
230 lines
6.7 KiB
Plaintext
/* Osmocom VTY interface functions in TTCN-3
|
|
* (C) 2017-2018 Harald Welte <laforge@gnumonks.org>
|
|
* contributions by sysmocom - s.f.m.c. GmbH
|
|
* All rights reserved.
|
|
*
|
|
* Released under the terms of GNU General Public License, Version 2 or
|
|
* (at your option) any later version.
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
module Osmocom_VTY_Functions {
|
|
|
|
import from Misc_Helpers all;
|
|
import from TELNETasp_PortType all;
|
|
import from Osmocom_Types all;
|
|
|
|
modulepar {
|
|
charstring mp_prompt_prefix := "OpenBSC";
|
|
float mp_prompt_timeout := 2.0;
|
|
}
|
|
|
|
const charstring VTY_VIEW_SUFFIX := "> ";
|
|
const charstring VTY_ENABLE_SUFFIX := "# ";
|
|
const charstring VTY_CFG_SUFFIX := "(*)";
|
|
|
|
template charstring t_vty_unknown := pattern "*% Unknown command.";
|
|
|
|
/* configure prompts in TELNETasp module */
|
|
function f_vty_set_prompts(TELNETasp_PT pt, charstring prompt_prefix := mp_prompt_prefix) {
|
|
var ASP_TelnetDynamicConfig vty_prompt[3] := {
|
|
{
|
|
prompt := {
|
|
id := 1,
|
|
prompt := prompt_prefix & VTY_VIEW_SUFFIX,
|
|
has_wildcards := false
|
|
}
|
|
}, {
|
|
prompt := {
|
|
id := 2,
|
|
prompt := prompt_prefix & VTY_ENABLE_SUFFIX,
|
|
has_wildcards := false
|
|
}
|
|
}, {
|
|
prompt := {
|
|
id := 3,
|
|
prompt := prompt_prefix & VTY_CFG_SUFFIX,
|
|
has_wildcards := true
|
|
}
|
|
}
|
|
};
|
|
|
|
/* set some configuration that isn't possible to express
|
|
* in the config file due to syntactic restrictions (Who invents config
|
|
* files that don't permit regular expressions? */
|
|
for (var integer i := 0; i < sizeof(vty_prompt); i:= i + 1) {
|
|
pt.send(vty_prompt[i]);
|
|
}
|
|
}
|
|
|
|
/* wait for any of the permitted prompts; buffer + return all intermediate output */
|
|
function f_vty_wait_for_prompt(TELNETasp_PT pt, boolean strict := true, charstring log_label := "(?)")
|
|
return charstring {
|
|
var charstring rx, buf := "";
|
|
var integer fd;
|
|
timer T;
|
|
|
|
T.start(mp_prompt_timeout);
|
|
alt {
|
|
[] pt.receive(pattern "[\w-]+" & VTY_VIEW_SUFFIX) { };
|
|
[] pt.receive(pattern "[\w-]+\# ") { };
|
|
[] pt.receive(pattern "[\w-]+\(*\)\# ") { };
|
|
[] pt.receive(t_vty_unknown) -> value rx {
|
|
if (strict) {
|
|
setverdict(fail, "VTY: Unknown Command: " & log_label);
|
|
mtc.stop;
|
|
} else {
|
|
log("VTY: Unknown Command (ignored): " & log_label);
|
|
buf := buf & rx;
|
|
repeat;
|
|
}
|
|
};
|
|
[] pt.receive(charstring:?) -> value rx { buf := buf & rx; repeat };
|
|
[] pt.receive(integer:?) -> value fd {
|
|
if (fd == -1) {
|
|
setverdict(fail, "VTY Telnet Connection Failure: " & log_label);
|
|
mtc.stop;
|
|
} else {
|
|
repeat; /* telnet connection succeeded */
|
|
}
|
|
}
|
|
[] T.timeout {
|
|
setverdict(fail, "VTY Timeout for prompt: " & log_label);
|
|
mtc.stop;
|
|
};
|
|
}
|
|
T.stop;
|
|
return buf;
|
|
}
|
|
|
|
/* send a VTY command and obtain response until prompt is received */
|
|
function f_vty_transceive_ret(TELNETasp_PT pt, charstring tx, boolean strict := true) return charstring {
|
|
pt.send(tx);
|
|
return f_vty_wait_for_prompt(pt, strict, tx);
|
|
}
|
|
|
|
/* send a VTY command and obtain response until prompt is received */
|
|
function f_vty_transceive(TELNETasp_PT pt, charstring tx, boolean strict := true) {
|
|
var charstring unused := f_vty_transceive_ret(pt, tx, strict);
|
|
}
|
|
|
|
type integer BtsNr (0..255);
|
|
type integer BtsTrxNr (0..255);
|
|
type integer BtsTimeslotNr (0..7);
|
|
type integer MscNr (0..255);
|
|
type integer Cs7Nr (0..255);
|
|
|
|
type charstring BtsGprsMode ("none", "gprs", "egrps");
|
|
|
|
/* enter the'confiugration' mode of the VTY */
|
|
function f_vty_enter_config(TELNETasp_PT pt) {
|
|
f_vty_transceive(pt, "configure terminal")
|
|
}
|
|
|
|
function f_vty_enter_cfg_network(TELNETasp_PT pt) {
|
|
f_vty_enter_config(pt);
|
|
f_vty_transceive(pt, "network")
|
|
}
|
|
|
|
function f_vty_enter_cfg_bts(TELNETasp_PT pt, BtsNr bts := 0) {
|
|
f_vty_enter_cfg_network(pt);
|
|
f_vty_transceive(pt, "bts " & int2str(bts));
|
|
}
|
|
|
|
function f_vty_enter_cfg_trx(TELNETasp_PT pt, BtsNr bts := 0, BtsTrxNr trx := 0) {
|
|
f_vty_enter_cfg_bts(pt, bts);
|
|
f_vty_transceive(pt, "trx " & int2str(trx));
|
|
}
|
|
|
|
function f_vty_enter_cfg_ts(TELNETasp_PT pt, BtsNr bts := 0, BtsTrxNr trx := 0, BtsTimeslotNr ts) {
|
|
f_vty_enter_cfg_trx(pt, bts, trx);
|
|
f_vty_transceive(pt, "timeslot " & int2str(ts));
|
|
}
|
|
|
|
function f_vty_enter_cfg_msc(TELNETasp_PT pt, MscNr msc := 0) {
|
|
f_vty_enter_config(pt);
|
|
f_vty_transceive(pt, "msc " & int2str(msc));
|
|
}
|
|
|
|
function f_vty_enter_cfg_cs7_inst(TELNETasp_PT pt, Cs7Nr cs7_inst := 0) {
|
|
f_vty_enter_config(pt);
|
|
f_vty_transceive(pt, "cs7 instance " & int2str(cs7_inst));
|
|
}
|
|
|
|
type record of charstring rof_charstring;
|
|
function f_vty_config3(TELNETasp_PT pt, rof_charstring config_nodes, rof_charstring cmds)
|
|
{
|
|
/* enter config mode; enter node */
|
|
f_vty_enter_config(pt);
|
|
for (var integer i := 0; i < sizeof(config_nodes); i := i+1) {
|
|
f_vty_transceive(pt, config_nodes[i]);
|
|
}
|
|
/* execute commands */
|
|
for (var integer i := 0; i < sizeof(cmds); i := i+1) {
|
|
f_vty_transceive(pt, cmds[i]);
|
|
}
|
|
/* leave config mode */
|
|
f_vty_transceive(pt, "end");
|
|
}
|
|
|
|
function f_vty_config2(TELNETasp_PT pt, rof_charstring config_nodes, charstring cmd)
|
|
{
|
|
f_vty_config3(pt, config_nodes, { cmd });
|
|
}
|
|
|
|
function f_vty_config(TELNETasp_PT pt, charstring config_node, charstring cmd)
|
|
{
|
|
f_vty_config2(pt, {config_node}, cmd);
|
|
}
|
|
|
|
function f_vty_cfg_bts(TELNETasp_PT pt, BtsNr bts := 0, rof_charstring cmds) {
|
|
f_vty_config3(pt, {"network", "bts " & int2str(bts)}, cmds);
|
|
}
|
|
|
|
function f_vty_cfg_msc(TELNETasp_PT pt, MscNr msc := 0, rof_charstring cmds) {
|
|
f_vty_config3(pt, {"msc " & int2str(msc)}, cmds);
|
|
}
|
|
|
|
function f_vty_transceive_match(TELNETasp_PT pt, charstring cmd, template charstring exp_ret) {
|
|
var charstring ret := f_vty_transceive_ret(pt, cmd);
|
|
if (not match(ret, exp_ret)) {
|
|
setverdict(fail, "Non-matching VTY response: ", ret);
|
|
mtc.stop;
|
|
}
|
|
}
|
|
|
|
function f_vty_transceive_not_match(TELNETasp_PT pt, charstring cmd, template charstring exp_ret) {
|
|
var charstring ret := f_vty_transceive_ret(pt, cmd);
|
|
if (match(ret, exp_ret)) {
|
|
setverdict(fail, "Unexpected matching VTY response: ", ret);
|
|
mtc.stop;
|
|
}
|
|
}
|
|
|
|
function f_vty_transceive_match_regex(TELNETasp_PT pt, charstring cmd, charstring regex, integer groupno) return charstring
|
|
{
|
|
var charstring resp := f_vty_transceive_ret(pt, cmd);
|
|
return regexp(resp, regex, groupno);
|
|
}
|
|
|
|
function f_vty_transceive_match_regexp_retry(TELNETasp_PT pt, charstring cmd, charstring regex,
|
|
integer groupno, integer num_attempts, float retry_delay) return charstring
|
|
{
|
|
while (num_attempts > 0) {
|
|
var charstring ret := f_vty_transceive_match_regex(pt, cmd, regex, groupno);
|
|
if (ret != "") {
|
|
return ret;
|
|
}
|
|
f_sleep(retry_delay);
|
|
num_attempts := num_attempts - 1;
|
|
}
|
|
|
|
Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
|
|
log2str("No matching VTY response for regular expression '",
|
|
regex, "' after ", num_attempts, " attempts." ));
|
|
return "";
|
|
}
|
|
|
|
}
|