[[common-control-if]] == Osmocom Control Interface The VTY interface as described in <> is aimed at human interaction with the respective Osmocom program. Other programs *should not* use the VTY interface to interact with the Osmocom software, as parsing the textual representation is cumbersome, inefficient, and will break every time the formatting is changed by the Osmocom developers. Instead, the 'Control Interface' was introduced as a programmatic interface that can be used to interact with the respective program. === Control Interface Protocol The control interface protocol is a mixture of binary framing with text based payload. The protocol for the control interface is wrapped inside the IPA multiplex header with the stream identifier set to IPAC_PROTO_OSMO (0xEE). .IPA header for control protocol [packetdiag] ---- { colwidth = 24 node_height = 24 0-15: Length (network byte order) 16-23: Stream ID (0xEE) } ---- Inside the IPA header is a single byte of extension header with protocol ID 0x00 which indicates the control interface. .IPA extension header for control protocol [packetdiag] ---- { colwidth = 8 node_height = 24 0-7: Protocol (0x00) } ---- After the concatenation of the two above headers, the plain-text payload message starts. The format of that plain text is illustrated for each operation in the respective message sequence chart in the chapters below. The fields specified below follow the following meaning: :: A numeric identifier, uniquely identifying this particular operation. Value `0` is not allowed unless it's a TRAP message. It will be echoed back in any response to a particular request. :: The name of the variable / field affected by the GET / SET / TRAP operation. Which variables/fields are available is dependent on the specific application under control. :: The value of the variable / field :: A text formatted, human-readable reason why the operation resulted in an error. ==== GET operation The GET operation is performed by an external application to get a certain value from inside the Osmocom application. .Control Interface GET operation (successful outcome) [mscgen] ---- msc { cli [label="Client"], ctrl [label="Control Interface"]; cli => ctrl [label="GET "]; cli <= ctrl [label="GET_REPLY "]; } ---- .Control Interface GET operation (unsuccessful outcome) [mscgen] ---- msc { cli [label="Client"], ctrl [label="Control Interface"]; cli => ctrl [label="GET "]; cli <= ctrl [label="ERROR "]; } ---- ==== SET operation The SET operation is performed by an external application to set a value inside the Osmocom application. .Control Interface SET operation (successful outcome) [mscgen] ---- msc { cli [label="Client"], ctrl [label="Control Interface"]; cli => ctrl [label="SET "]; cli <= ctrl [label="SET_REPLY "]; } ---- .Control Interface SET operation (unsuccessful outcome) [mscgen] ---- msc { cli [label="Client"], ctrl [label="Control Interface"]; cli => ctrl [label="SET "]; cli <= ctrl [label="ERROR "]; } ---- ==== TRAP operation The program can at any time issue a trap. The term is used in the spirit of SNMP. .Control Interface TRAP operation [mscgen] ---- msc { cli [label="Client"], ctrl [label="Control Interface"]; cli <= ctrl [label="TRAP "]; } ---- [[ctrl_common_vars]] === Common variables There are several variables which are common to all the programs using control interface. They are described in the following table. .Variables available over control interface [options="header",width="100%",cols="20%,10%,50%,20%"] |=== |Name|Access|Value|Comment |counter.*|RO||Get counter value. |rate_ctr.*|RO||Get list of rate counter groups. |rate_ctr.IN.GN.GI.name|RO||Get value for interval IN of rate counter name which belong to group named GN with index GI. |=== Those read-only variables allow to get value of arbitrary counter using its name. For example "+rate_ctr.per_hour.bsc.0.handover:timeout+" is the number of handover timeouts per hour. Of course for that to work the program in question have to register corresponding counter names and groups using libosmocore functions. In the example above, "+bsc+" is the rate counter group name and "+0+" is its index. It is possible to obtain all the rate counters in a given group by requesting "+rate_ctr.per_sec.bsc.*+" variable. The list of available groups can be obtained by requesting "+rate_ctr.*+" variable. The rate counter group name have to be prefixed with interval specification which can be any of "*per_sec*", "*per_min*", "*per_hour*", "*per_day*" or "*abs*" for absolute value. The old-style counters available via "+counter.*+" variables are superseded by "+rate_ctr.abs+" so its use is discouraged. There might still be some applications not yet converted to rate_ctr. === Control Interface python examples In the `osmo-python-tests` repository, there is an example python script called `scripts/osmo_ctrl.py` which implements the Osmocom control interface protocol. You can use this tool either stand-alone to perform control interface operations against an Osmocom program, or you can use it as a reference for developing your own python software talking to the control interface. Another implementation is in `scripts/osmo_rate_ctr2csv.py` which will retrieve performance counters for a given Osmocom program and output it in csv format. This can be used to periodically (using systemd timer for example) retrieve data to build KPI and evaluate how it changes over time. Internally it uses "+rate_ctr.*+" variable described in <> to get the list of counter groups and than request all the counters in each group. Applications interested in individual metrics can request it directly using `rate_ctr2csv.py` as an example. ==== Getting rate counters .Example: Use `rate_ctr2csv.py` to get rate counters from OsmoBSC ---- $ ./scripts/osmo_rate_ctr2csv.py --header Connecting to localhost:4249... Getting rate counter groups info... "group","counter","absolute","second","minute","hour","day" "e1inp.0","hdlc:abort","0","0","0","0","0" "e1inp.0","hdlc:bad_fcs","0","0","0","0","0" "e1inp.0","hdlc:overrun","0","0","0","0","0" "e1inp.0","alarm","0","0","0","0","0" "e1inp.0","removed","0","0","0","0","0" "bsc.0","chreq:total","0","0","0","0","0" "bsc.0","chreq:no_channel","0","0","0","0","0" ... "msc.0","call:active","0","0","0","0","0" "msc.0","call:complete","0","0","0","0","0" "msc.0","call:incomplete","0","0","0","0","0" Completed: 44 counters from 3 groups received. ---- ==== Setting a value .Example: Use `osmo_ctrl.py` to set the short network name of OsmoBSC ---- $ ./osmo_ctrl.py -d localhost -s short-name 32C3 Got message: SET_REPLY 1 short-name 32C3 ---- ==== Getting a value .Example: Use `osmo_ctrl.py` to get the mnc of OsmoBSC ---- $ ./osmo_ctrl.py -d localhost -g mnc Got message: GET_REPLY 1 mnc 262 ---- ==== Listening for traps You can use `osmo_ctrl.py` to listen for traps the following way: .Example: Using `osmo_ctrl.py` to listen for traps: ---- $ ./osmo_ctrl.py -d localhost -m <1> ---- <1> the command will not return and wait for any TRAP messages to arrive