Guest Shell on Catalyst 9800

Cisco Guest Shell is a virtual Linux environment available on certain Cisco devices, it includes Python and provides a platform for hosting and running scripts directly on the device. This blog explores some telemetry options using Guest Shell on Catalyst 9800 wireless controller.

The first task is to start the guestshell.

WLC9800#conf t
WLC9800(config)#iox
WLC9800(config-app-hosting)#app-hosting appid guestshell
WLC9800(config-app-hosting-mgmt-gateway)#app-vnic management guest-interface 0
WLC9800#guestshell enable

Unlike other guestshell enabled devices, the 9800 WLC does not (at least currently) allow for mapping of the controller management interface (or any in-line interface for that matter) to the virtual Linux system (as a vnic). Only the service port is supported. This means that if your script needs to be reachable from outside of the device, or itself needs to reach the outside world, that can only happen through the out-of-band service port. The example demonstrated further down will need such reachability – so a service port link is required.  <insert UTP click sound>

Next, verify that CAF, IOxman, and Libvirtd services are running.

WLC9800#sh iox
IOx Infrastructure Summary:
---------------------------
IOx service (CAF)              : Running
IOx service (HA)               : Not Supported
IOx service (IOxman)           : Running
IOx service (Sec storage)      : Not Supported
Libvirtd 5.5.0                 : Running

All good so far, now let’s access the Linux system, CentOS in this case.   

WLC9800#guestshell
[guestshell@guestshell ~]$
[guestshell@guestshell ~]$ hostnamectl
   Static hostname: guestshell
         Icon name: computer-container
           Chassis: container
        Machine ID: 0e44cd6d7cab4a25896b5e683ecea8e5
           Boot ID: 8798853597674f7bb049c961377a803d
    Virtualization: lxc-libvirt
  Operating System: CentOS Stream 8
       CPE OS Name: cpe:/o:centos:centos:8
            Kernel: Linux 5.4.159
      Architecture: x86-64

For our Linux system to be useful it needs a DNS server. This is done by editing /etc/resolv.conf and adding a nameserver entry. Caveat here, the resolv.conf file does not survive a restart of the guestshell.

VI is the text editor included in guestshell by default, but once the guestshell has reachability to the outside world it is relatively straightforward to add new packages using Yum.

Extra packages used for this demo:

  • Git (to clone the code repo, avoiding TFTP / USB file transfers)
  • Nano (optional)

Now is also a good time to install any Python libraries, depending on what the given automation will need, in this case it’s going to be the Requests library (installed using pip).

Speaking of Python libraries, guestshell comes packaged with the CLI library used for running CLI commands on the device. This is necessary for extracting command output from the device into our Python script(s). Basic operation (in Python) is as follows:

import cli
device_output = cli.cli("show version")

Another caveat here, every output of the CLI module is logged to /data/iosp.log. This means that the log file will keep growing the longer you run your script, eventually resulting in something like this:

OSError: [Errno 28] No space left on device

We can work around this by disabling CLI logging, this can be done by editing /usr/lib/python3.6/site-packages/cli/__init__.py and changing LOGFILE = None (this change also does not survive a restart of the guestshell).

OK, so to sum up the key steps so far.

  • Enable guestshell
  • Configure DNS
  • Install required Linux & Python modules
  • Disable logging

Now we can get to automating stuff.

For this demo let’s create a script that collects some RF statistics from the WLC and sends them via API call to a monitoring system. Specifically, the show ap auto-rf dot11 5ghz command as it gives us some handy information about the state of the network. This command cannot be run per-AP, meaning that it is potentially a long output depending on the number of APs attached to the WLC, we will need to parse all of it every time, however, this processing will be done within guestshell (at the edge) resulting in a relatively small payload sent to the monitoring system.

All the code used here is available on https://github.com/Johnny8Bit/guestshell9800

On the WLC, clone the repo.

git clone https://github.com/Johnny8Bit/guestshell9800

Edit datastream.py and set basic variable(s), i.e., IP of monitoring system.

monitor_ip = "192.168.1.6"

Run the data streaming script, either

from inside the guestshell.

[guestshell@guestshell ~]$ python3 /home/guestshell/guestshell9800/datastream.py
192.168.1.6 Timeout
192.168.1.6 Timeout

or from outside the guestshell.

WLC9800#guestshell run python3 /home/guestshell/guestshell9800/datastream.py
192.168.1.6 Timeout
192.168.1.6 Timeout

The timeouts are due to the receiving end of the application not being started yet. The repository contains two versions of the monitor application, a text-based version using the tabulate Python module (textmonitor.py) and a web version (webmonitor.py). Both are Flask applications responsible for receiving the data from the WLC and displaying it. The web version uses simple CSS from http://getskeleton.com/.

Start the receiving app on a local workstation using the Flask development web server.

python3 webmonitor.py

The guestshell script should now be returning a 200 status code. Now point a browser to the webmonitor application.

And that’s it, the Python script running in a virtual machine on the WLC is collecting data from the WLC, and sending that via API call to a web application. From the single CLI command we get a list of top 20 APs sorted by channel utilization, along with additional information showing client count and the number channel changes on each radio. The page auto-refreshes, refresh frequency as well as frequency of CLI execution can be easily adjusted.

For larger or more permanent deployments a telemetry configuration using something like Grafana would be more scalable, this example does however demonstrate the possibilities guestshell provides by making it possible to run Python directly on the network device.