This post has been on my backlog for a while... I've been intermittently trying out the IOS-XE guestshell feature for a few different projects, and never feeling like any of them were good enough to write about.
So why not just write about guestshell itself? It's such a nifty tool.
What is Guestshell?
Now that Cisco's Catalyst platform has standardized on IOS-XE, we can take advantage of some of the features of the Linux-based platform. One of which being Linux Containers (LXC).
Most of the latest Catalyst routers, switches, and access points support what Cisco calls Application Hosting - which is a fancy way of just saying it can run containers on-box. Another acronym to be aware of is IOx - which is what Cisco calls their IOS-XE/Linux appliction framework.
Guestshell is a specific feature within IOS-XE, where a dedicated pre-built container is enabled for on-box access to a Linux shell.
What Hardware Supports Guestshell?
Okay - so for this example, I'll be using the new Catalyst 8000V platform (a virtual Catalyst router). I do also have a Catalyst 9200L on hand, but unfortunately it's one of the few Catalyst platforms that does not support Guestshell (due to lower-end HW specs).
You can also use the Catalyst 8000V to test this in a lab, or you could use most of the Catalyst 8000 / 9000 series platforms if you had them available (or the CSRv & some ISR routers!).
You can find a list of supported platforms & other hardware requirements here.
All that being said - let's get started!
So before we can actually use the guestshell feature, there is some pre-configuration to be done.
First we'll need to ensure that the IOx application framework is enabled & running. We can check this by using the show iox command:
0x8KV01# show iox IOx Infrastructure Summary: --------------------------- IOx service (CAF) : Not Running IOx service (HA) : Not Supported IOx service (IOxman) : Not Running IOx service (Sec storage) : Not Supported Libvirtd 5.5.0 : Running
And as we see above - most components are listed as "Not Running" or "Not Supported".
So we'll enter config mode, and use the iox command to enable these services:
0x8KV01# conf t Enter configuration commands, one per line. End with CNTL/Z. 0x8KV01(config)# iox 0x8KV01(config)# 0x8KV01(config)# exit 0x8KV01# show 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
Configuring Guestshell Networking
There's a good chance we'll want our container to have access to the outside world, so let's take a quick look at the network configuration.
Note: The networking config syntax will differ if you are using a Catalyst router or a Catalyst switch. Since I am using a Catalyst 8000V - we will look at the config for a Catalyst router first.
In order to allow external access to our container, we'll need to configure a gateway interface and NAT translations. Then we can provide a full network configuration to our container:
## Enable NAT on our external interface - in my case, gigabitEthernet1 0x8KV01(config)# interface gigabitEthernet 1 0x8KV01(config-if)# ip nat outside ## Create a virtual interface for the guestshell container 0x8KV01(config-if)# int virtualportgroup0 0x8KV01(config-if)# ip address 192.168.100.1 255.255.255.0 0x8KV01(config-if)# ip nat inside ## Create an ACL to match traffic from guestshell & Enable NAT 0x8KV01(config)# ip access-list standard IOX_NAT 0x8KV01(config-std-nacl)# permit 192.168.100.0 0.0.0.255 0x8KV01(config)# ip nat inside source list IOX_NAT interface gigabitEthernet 1 overload ## Assign network configuration to our guestshell container 0x8KV01(config)#app-hosting appid guestshell 0x8KV01(config-app-hosting)# app-vnic gateway0 virtualportgroup 0 guest-interface 0 0x8KV01(config-app-hosting-gateway0)# guest-ipaddress 192.168.100.5 netmask 255.255.255.0 0x8KV01(config-app-hosting-gateway0)# app-default-gateway 192.168.100.1 guest-interface 0 0x8KV01(config-app-hosting)# name-server0 220.127.116.11
Now, as I mentioned before - this config will look different if you're using a switch vs a router.
So let's take a quick look at what this would look like, if we were on a Catalyst Switch instead:
Cat9k(config)# interface AppGigabitEthernet 1/0/1 Cat9k(config-if)# switchport mode trunk Cat9k(config)# app-hosting appid name Cat9k(config-app-hosting)# app-vnic AppGigabitEthernet trunk Cat9k(config-app-hosting-trunk)# vlan 10 guest-interface 0 Cat9k(config-app-hosting-vlan-access-ip))# guest-ipaddress 192.168.100.1 netmask 255.255.255.0 Cat9k(config-app-hosting)# app-default-gateway 192.168.100.1 guest-interface 0 Cat9k(config)# name-server 18.104.22.168
Once all that config is done - Let's move on to getting our container started!!
Managing the Guestshell Process
In order to start a container on our Catalyst device, we'll need to go through a process of deploying the app, activating it, then starting it.
For guestshell, there is a shortcut command that will perform all of these steps for you - and make managing the guestshell process much easier.
So let's go ahead and spin up our guestshell container with the command guestshell enable:
0x8KV01# guestshell enable Interface will be selected if configured in app-hosting Please wait for completion guestshell installed successfully Current state is: DEPLOYED guestshell activated successfully Current state is: ACTIVATED guestshell started successfully Current state is: RUNNING Guestshell enabled successfully 0x8KV01# show app-hosting list App id State --------------------------------------------------------- guestshell RUNNING
And as you can see above, everything gets automatically deployed & started. We can verify using the show app-hosting list command to see that our container has been started.
If we need to, we can also stop & deactivate our container using the command guestshell disable.
We could also use the commands below if we wanted to perform these steps manually:
0x8KV01# app-hosting activate appid guestshell 0x8KV01# app-hosting start appid guestshell 0x8KV01# app-hosting stop appid guestshell 0x8KV01# app-hosting deactivate appid guestshell
Before we move onto accessing the guestshell interface, I also wanted to show where you can get more detail about the guestshell container.
Using the show app-hosting detail appid guestshell command, we can see details around the container version, current MAC/IP config, and resource consumption:
0x8KV01# show app-hosting detail appid guestshell App id : guestshell Owner : iox State : RUNNING Application Type : lxc Name : GuestShell Version : 3.2.0 Description : Cisco Systems Guest Shell XE for x86_64 Path : /guestshell/:guestshell.tar URL Path : Activated profile name : custom Resource reservation Memory : 256 MB Disk : 1 MB CPU : 800 units CPU-percent : 3 % VCPU : 1 Attached devices Type Name Alias --------------------------------------------- serial/shell iox_console_shell serial0 serial/aux iox_console_aux serial1 serial/syslog iox_syslog serial2 serial/trace iox_trace serial3 Network interfaces --------------------------------------- eth0: MAC address : 52:54:dd:d:bf:da IPv4 address : 192.168.100.5 IPv6 address : :: Network name : VPG0 Port forwarding Table-entry Service Source-port Destination-port ---------------------------------------------------
Accessing the Guestshell CLI
Now for the fun part! Let's get into our guestshell container.
We'll just need to use the guestshell command, and we'll be dropped into the Linux shell:
0x8KV01# guestshell [[email protected] ~]$ [[email protected] ~]$ uname -a Linux guestshell 5.4.40 #1 SMP Tue Oct 6 17:57:00 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
Let's also make sure our network & NAT configuration worked:
[[email protected] ~]$ ping 22.214.171.124 PING 126.96.36.199 (188.8.131.52) 56(84) bytes of data. 64 bytes from 184.108.40.206: icmp_seq=1 ttl=64 time=3.57 ms 64 bytes from 220.127.116.11: icmp_seq=2 ttl=64 time=2.64 ms 64 bytes from 18.104.22.168: icmp_seq=3 ttl=64 time=2.54 ms ^C --- 22.214.171.124 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 4ms rtt min/avg/max/mdev = 2.543/2.916/3.567/0.465 ms
If needed, we can also run commands on our Catalyst device CLI without leaving the guestshell interface by using the dohost utility:
[[email protected] ~]$ dohost "show app-hosting list" App id State --------------------------------------------------------- guestshell RUNNING [[email protected] ~]$
Just a note, the reverse is also possible. Using the guestshell run command from our Catalyst CLI, we can run commands in our container:
0x8KV01# guestshell run uname -a Linux guestshell 5.4.40 #1 SMP Tue Oct 6 17:57:00 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux 0x8KV01#
It's also worth reiterating, that the guestshell container is a full Linux container (It runs CentOS). So if we need to install additional Linux packages, we can use our Linux package manager (YUM) to do so.
Anyways - Let's wrap this up by looking at the built-in Python modules & capabilities
Using Python in Guestshell
One of the more appealing use cases for guestshell is the ability to run native Python scripts & code directly on your Catalyst device.
A couple of possible use cases could be:
- Troubleshoot intermittent issues - Automatically collect device state (routes, MAC changes, etc) on a regular basis to log locally or send via email
- Automated resolution - If a certain type of state change is observed, we could run a pre-set list of commands to try and automatically fix the issue
- Local monitoring / troubleshooting - We could run a series of ping, web page load tests, etc from a python script to help monitor performance from the switch's perspective
- Change management / notification - A script could be written to monitor the device configuration for any changes made, then send an automated email when something was detected
- Have a risky change that might sever your connection to a remote device? A script could execute the change for you, and if unsuccessful, revert to a working configuration (without doing a reload after)
These are just a handful of ideas that came to mind while writing this blog post... But there are many more possibilities!
Within the guestshell container, there is a special cli python module that comes pre-loaded. This module allows us to run CLI commands on our catalyst device directly from a python script & receive the command output for parsing.
Let's look at a quick example using the Python interactive interpreter to save the device configuration:
[[email protected] ~]$ python3 Python 3.6.8 (default, Aug 24 2020, 17:57:11) [GCC 8.3.1 20191121 (Red Hat 8.3.1-5)] on linux Type "help", "copyright", "credits" or "license" for more information. >>> >>> import cli >>> status = cli.execute("write memory") >>> if "OK" in status: print("Device configuration was saved!") ... Device configuration was saved!
The example above uses the cli.execute Python function, which will run commands in Cisco's exec mode.
What if we wanted to make configuration changes? In that case we would use the cli.configure function:
>>> config_data = """interface loopback200 ... ip address 172.16.99.10 255.255.255.0 ... """ >>> >>> cli.configure(config_data) 'Line 1 SUCCESS: interface loopback200\nLine 2 SUCCESS: ip address 172.16.99.10 255.255.255.0\n' >>> >>> cli.execute("show run interface loopback200") 'Building configuration...\nCurrent configuration : 68 bytes\n!\ninterface Loopback200\n ip address 172.16.99.10 255.255.255.0\nend\n'
In the above example, we used a multi-line comment to provide the list of commands to enter. The cli.configure function also supports a Python list - so we could provide the commands in that format as well.
You'll notice that the Python interpreter returns a status for each command that we attempted to run. This should allow us to error-check & ensure that all of our intended configuration was accepted.
Lastly, we used the cli.execute command again to validate that our running configuration looks correct.
There's a bit more functionality built into the cli Python module, but I just wanted to cover some of the common use cases. More details can be found here
A Few Common Questions...
Does this give me access to the underlying IOS-XE Linux shell?
Nope, anything running in guestshell is running in a container - which runs on-top of the IOS-XE image.
What about resource conflicts?
The linux containers running on the IOS-XE platform are given their own dedicated resources. Any resource constraints that affect the containers will not impact normal network functions.