<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Cli on 0x2142 | Networking Nonsense</title>
    <link>https://0x2142.com/tags/cli/</link>
    <description>Recent content in Cli on 0x2142 | Networking Nonsense</description>
    <image>
      <title>0x2142 | Networking Nonsense</title>
      <url>https://0x2142.com/logo.jpg</url>
      <link>https://0x2142.com/logo.jpg</link>
    </image>
    <generator>Hugo -- 0.143.1</generator>
    <language>en-us</language>
    <lastBuildDate>Tue, 26 Jan 2021 16:15:41 +0000</lastBuildDate>
    <atom:link href="https://0x2142.com/tags/cli/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Getting Started with IOS-XE Guestshell</title>
      <link>https://0x2142.com/getting-started-with-ios-xe-guestshell/</link>
      <pubDate>Tue, 26 Jan 2021 16:15:41 +0000</pubDate>
      <guid>https://0x2142.com/getting-started-with-ios-xe-guestshell/</guid>
      <description>In this post, we&amp;rsquo;ll explore how to set up Cisco IOX &amp;amp; Guestshell for on-box Python</description>
      <content:encoded><![CDATA[<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
      <iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="allowfullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/KiVbDq0Czdg?autoplay=0&amp;controls=1&amp;end=0&amp;loop=0&amp;mute=0&amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"></iframe>
    </div>

<p>This post has been on my backlog for a while&hellip; I&rsquo;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.</p>
<p>So why not just write about guestshell itself? It&rsquo;s such a nifty tool.</p>
<hr>
<h2 id="what-is-guestshell">What is Guestshell?</h2>
<p>Now that Cisco&rsquo;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).</p>
<p>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.</p>
<p>Guestshell is a specific feature within IOS-XE, where a dedicated pre-built container is enabled for on-box access to a Linux shell.</p>
<h2 id="what-hardware-supports-guestshell">What Hardware Supports Guestshell?</h2>
<p>Okay - so for this example, I&rsquo;ll be using the new Catalyst 8000V platform (a virtual Catalyst router). I do also have a Catalyst 9200L on hand, but unfortunately it&rsquo;s one of the few Catalyst platforms that <em>does not</em> support Guestshell (due to lower-end HW specs).</p>
<p>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 &amp; some ISR routers!).</p>
<p>You can find a list of supported platforms &amp; other hardware requirements <a href="https://www.cisco.com/c/en/us/td/docs/ios-xml/ios/prog/configuration/166/b_166_programmability_cg/guest_shell.html#id_45838">here</a>.</p>
<p>All that being said - let&rsquo;s get started!</p>
<h2 id="enabling-iox">Enabling IOx</h2>
<p>So before we can actually use the guestshell feature, there is some pre-configuration to be done.</p>
<p>First we&rsquo;ll need to ensure that the IOx application framework is enabled &amp; running. We can check this by using the <strong>show iox</strong> command:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0x8KV01# show iox
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">IOx Infrastructure Summary:
</span></span><span class="line"><span class="cl">---------------------------
</span></span><span class="line"><span class="cl">IOx service (CAF)              : Not Running
</span></span><span class="line"><span class="cl">IOx service (HA)               : Not Supported
</span></span><span class="line"><span class="cl">IOx service (IOxman)           : Not Running
</span></span><span class="line"><span class="cl">IOx service (Sec storage)      : Not Supported
</span></span><span class="line"><span class="cl">Libvirtd 5.5.0                 : Running
</span></span></code></pre></div><p>And as we see above - most components are listed as &ldquo;Not Running&rdquo; or &ldquo;Not Supported&rdquo;.</p>
<p>So we&rsquo;ll enter config mode, and use the <em>iox</em> command to enable these services:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0x8KV01# conf t
</span></span><span class="line"><span class="cl">Enter configuration commands, one per line.  End with CNTL/Z.
</span></span><span class="line"><span class="cl">0x8KV01(config)# iox 
</span></span><span class="line"><span class="cl">0x8KV01(config)#
</span></span><span class="line"><span class="cl">0x8KV01(config)# exit
</span></span><span class="line"><span class="cl">0x8KV01# show iox
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">IOx Infrastructure Summary:
</span></span><span class="line"><span class="cl">---------------------------
</span></span><span class="line"><span class="cl">IOx service (CAF)              : Running
</span></span><span class="line"><span class="cl">IOx service (HA)               : Not Supported
</span></span><span class="line"><span class="cl">IOx service (IOxman)           : Running
</span></span><span class="line"><span class="cl">IOx service (Sec storage)      : Not Supported
</span></span><span class="line"><span class="cl">Libvirtd 5.5.0                 : Running
</span></span></code></pre></div><h2 id="configuring-guestshell-networking">Configuring Guestshell Networking</h2>
<p>There&rsquo;s a good chance we&rsquo;ll want our container to have access to the outside world, so let&rsquo;s take a quick look at the network configuration.</p>
<p><strong>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.</strong></p>
<p>In order to allow external access to our container, we&rsquo;ll need to configure a gateway interface and NAT translations. Then we can provide a full network configuration to our container:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">## Enable NAT on our external interface - in my case, gigabitEthernet1
</span></span><span class="line"><span class="cl">0x8KV01(config)# interface gigabitEthernet 1
</span></span><span class="line"><span class="cl">0x8KV01(config-if)# ip nat outside
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">## Create a virtual interface for the guestshell container
</span></span><span class="line"><span class="cl">0x8KV01(config-if)# int virtualportgroup0
</span></span><span class="line"><span class="cl">0x8KV01(config-if)# ip address 192.168.100.1 255.255.255.0
</span></span><span class="line"><span class="cl">0x8KV01(config-if)# ip nat inside
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">## Create an ACL to match traffic from guestshell &amp; Enable NAT
</span></span><span class="line"><span class="cl">0x8KV01(config)# ip access-list standard IOX_NAT
</span></span><span class="line"><span class="cl">0x8KV01(config-std-nacl)# permit 192.168.100.0 0.0.0.255
</span></span><span class="line"><span class="cl">0x8KV01(config)# ip nat inside source list IOX_NAT interface gigabitEthernet 1 overload
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">## Assign network configuration to our guestshell container
</span></span><span class="line"><span class="cl">0x8KV01(config)#app-hosting appid guestshell
</span></span><span class="line"><span class="cl">0x8KV01(config-app-hosting)# app-vnic gateway0 virtualportgroup 0 guest-interface 0
</span></span><span class="line"><span class="cl">0x8KV01(config-app-hosting-gateway0)# guest-ipaddress 192.168.100.5 netmask 255.255.255.0
</span></span><span class="line"><span class="cl">0x8KV01(config-app-hosting-gateway0)# app-default-gateway 192.168.100.1 guest-interface 0
</span></span><span class="line"><span class="cl">0x8KV01(config-app-hosting)# name-server0 8.8.8.8
</span></span></code></pre></div><p>Now, as I mentioned before - this config will look different if you&rsquo;re using a switch vs a router.</p>
<p>So let&rsquo;s take a quick look at what this would look like, if we were on a Catalyst Switch instead:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Cat9k(config)# interface AppGigabitEthernet 1/0/1
</span></span><span class="line"><span class="cl">Cat9k(config-if)# switchport mode trunk
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Cat9k(config)# app-hosting appid name
</span></span><span class="line"><span class="cl">Cat9k(config-app-hosting)# app-vnic AppGigabitEthernet trunk
</span></span><span class="line"><span class="cl">Cat9k(config-app-hosting-trunk)# vlan 10 guest-interface 0
</span></span><span class="line"><span class="cl">Cat9k(config-app-hosting-vlan-access-ip))# guest-ipaddress 192.168.100.1 netmask 255.255.255.0
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Cat9k(config-app-hosting)# app-default-gateway 192.168.100.1 guest-interface 0
</span></span><span class="line"><span class="cl">Cat9k(config)# name-server 8.8.8.8 
</span></span></code></pre></div><p>Once all that config is done - Let&rsquo;s move on to getting our container started!!</p>
<h2 id="managing-the-guestshell-process">Managing the Guestshell Process</h2>
<p>In order to start a container on our Catalyst device, we&rsquo;ll need to go through a process of deploying the app, activating it, then starting it.</p>
<p>For guestshell, there is a shortcut command that will perform all of these steps for you - and make managing the guestshell process much easier.</p>
<p>So let&rsquo;s go ahead and spin up our guestshell container with the command <strong>guestshell enable</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0x8KV01# guestshell enable
</span></span><span class="line"><span class="cl">Interface will be selected if configured in app-hosting
</span></span><span class="line"><span class="cl">Please wait for completion
</span></span><span class="line"><span class="cl">guestshell installed successfully
</span></span><span class="line"><span class="cl">Current state is: DEPLOYED
</span></span><span class="line"><span class="cl">guestshell activated successfully
</span></span><span class="line"><span class="cl">Current state is: ACTIVATED
</span></span><span class="line"><span class="cl">guestshell started successfully
</span></span><span class="line"><span class="cl">Current state is: RUNNING
</span></span><span class="line"><span class="cl">Guestshell enabled successfully
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">0x8KV01# show app-hosting list
</span></span><span class="line"><span class="cl">App id                                   State
</span></span><span class="line"><span class="cl">---------------------------------------------------------
</span></span><span class="line"><span class="cl">guestshell                               RUNNING
</span></span></code></pre></div><p>And as you can see above, everything gets automatically deployed &amp; started. We can verify using the <strong>show app-hosting list</strong> command to see that our container has been started.</p>
<p>If we need to, we can also stop &amp; deactivate our container using the command <strong>guestshell disable</strong>.</p>
<p>We could also use the commands below if we wanted to perform these steps manually:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0x8KV01# app-hosting activate appid guestshell
</span></span><span class="line"><span class="cl">0x8KV01# app-hosting start appid guestshell
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">0x8KV01# app-hosting stop appid guestshell
</span></span><span class="line"><span class="cl">0x8KV01# app-hosting deactivate appid guestshell
</span></span></code></pre></div><p>Before we move onto accessing the guestshell interface, I also wanted to show where you can get more detail about the guestshell container.</p>
<p>Using the <strong>show app-hosting detail appid guestshell</strong> command, we can see details around the container version, current MAC/IP config, and resource consumption:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0x8KV01# show app-hosting detail appid guestshell
</span></span><span class="line"><span class="cl">App id                 : guestshell
</span></span><span class="line"><span class="cl">Owner                  : iox
</span></span><span class="line"><span class="cl">State                  : RUNNING
</span></span><span class="line"><span class="cl">Application
</span></span><span class="line"><span class="cl">  Type                 : lxc
</span></span><span class="line"><span class="cl">  Name                 : GuestShell
</span></span><span class="line"><span class="cl">  Version              : 3.2.0
</span></span><span class="line"><span class="cl">  Description          : Cisco Systems Guest Shell XE for x86_64
</span></span><span class="line"><span class="cl">  Path                 : /guestshell/:guestshell.tar
</span></span><span class="line"><span class="cl">  URL Path             :
</span></span><span class="line"><span class="cl">Activated profile name : custom
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Resource reservation
</span></span><span class="line"><span class="cl">  Memory               : 256 MB
</span></span><span class="line"><span class="cl">  Disk                 : 1 MB
</span></span><span class="line"><span class="cl">  CPU                  : 800 units
</span></span><span class="line"><span class="cl">  CPU-percent          : 3 %
</span></span><span class="line"><span class="cl">  VCPU                 : 1
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Attached devices
</span></span><span class="line"><span class="cl">  Type              Name               Alias
</span></span><span class="line"><span class="cl">  ---------------------------------------------
</span></span><span class="line"><span class="cl">  serial/shell     iox_console_shell   serial0
</span></span><span class="line"><span class="cl">  serial/aux       iox_console_aux     serial1
</span></span><span class="line"><span class="cl">  serial/syslog    iox_syslog          serial2
</span></span><span class="line"><span class="cl">  serial/trace     iox_trace           serial3
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Network interfaces
</span></span><span class="line"><span class="cl">   ---------------------------------------
</span></span><span class="line"><span class="cl">eth0:
</span></span><span class="line"><span class="cl">   MAC address         : 52:54:dd:d:bf:da
</span></span><span class="line"><span class="cl">   IPv4 address        : 192.168.100.5
</span></span><span class="line"><span class="cl">   IPv6 address        : ::
</span></span><span class="line"><span class="cl">   Network name        : VPG0
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Port forwarding
</span></span><span class="line"><span class="cl">  Table-entry  Service  Source-port  Destination-port
</span></span><span class="line"><span class="cl">  ---------------------------------------------------
</span></span></code></pre></div><h2 id="accessing-the-guestshell-cli">Accessing the Guestshell CLI</h2>
<p>Now for the fun part! Let&rsquo;s get into our guestshell container.</p>
<p>We&rsquo;ll just need to use the <strong>guestshell</strong> command, and we&rsquo;ll be dropped into the Linux shell:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0x8KV01# guestshell
</span></span><span class="line"><span class="cl">[guestshell@guestshell ~]$
</span></span><span class="line"><span class="cl">[guestshell@guestshell ~]$ uname -a
</span></span><span class="line"><span class="cl">Linux guestshell 5.4.40 #1 SMP Tue Oct 6 17:57:00 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
</span></span></code></pre></div><p>Let&rsquo;s also make sure our network &amp; NAT configuration worked:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">[guestshell@guestshell ~]$ ping 8.8.8.8
</span></span><span class="line"><span class="cl">PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
</span></span><span class="line"><span class="cl">64 bytes from 8.8.8.8: icmp_seq=1 ttl=64 time=3.57 ms
</span></span><span class="line"><span class="cl">64 bytes from 8.8.8.8: icmp_seq=2 ttl=64 time=2.64 ms
</span></span><span class="line"><span class="cl">64 bytes from 8.8.8.8: icmp_seq=3 ttl=64 time=2.54 ms
</span></span><span class="line"><span class="cl">^C
</span></span><span class="line"><span class="cl">--- 8.8.8.8 ping statistics ---
</span></span><span class="line"><span class="cl">3 packets transmitted, 3 received, 0% packet loss, time 4ms
</span></span><span class="line"><span class="cl">rtt min/avg/max/mdev = 2.543/2.916/3.567/0.465 ms
</span></span></code></pre></div><p>If needed, we can also run commands on our Catalyst device CLI without leaving the guestshell interface by using the <strong>dohost</strong> utility:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">[guestshell@guestshell ~]$ dohost &#34;show app-hosting list&#34;
</span></span><span class="line"><span class="cl">App id                                   State
</span></span><span class="line"><span class="cl">---------------------------------------------------------
</span></span><span class="line"><span class="cl">guestshell                               RUNNING
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">[guestshell@guestshell ~]$
</span></span></code></pre></div><p>Just a note, the reverse is also possible. Using the <strong>guestshell run</strong> command from our Catalyst CLI, we can run commands in our container:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0x8KV01# guestshell run uname -a
</span></span><span class="line"><span class="cl">Linux guestshell 5.4.40 #1 SMP Tue Oct 6 17:57:00 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">0x8KV01#
</span></span></code></pre></div><p>It&rsquo;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.</p>
<p>Anyways - Let&rsquo;s wrap this up by looking at the built-in Python modules &amp; capabilities</p>
<h2 id="using-python-in-guestshell">Using Python in Guestshell</h2>
<p>One of the more appealing use cases for guestshell is the ability to run native Python scripts &amp; code directly on your Catalyst device.</p>
<p>A couple of possible use cases could be:</p>
<ul>
<li>Troubleshoot intermittent issues - Automatically collect device state (routes, MAC changes, etc) on a regular basis to log locally or send via email</li>
<li>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</li>
<li>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&rsquo;s perspective</li>
<li>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</li>
<li>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 <em>reload after</em>)</li>
</ul>
<p>These are just a handful of ideas that came to mind while writing this blog post&hellip; But there are many more possibilities!</p>
<p>Within the guestshell container, there is a special <strong>cli</strong> python module that comes pre-loaded. This module allows us to run CLI commands on our catalyst device directly from a python script &amp; receive the command output for parsing.</p>
<p>Let&rsquo;s look at a quick example using the Python interactive interpreter to save the device configuration:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">[guestshell@guestshell ~]$ python3
</span></span><span class="line"><span class="cl">Python 3.6.8 (default, Aug 24 2020, 17:57:11)
</span></span><span class="line"><span class="cl">[GCC 8.3.1 20191121 (Red Hat 8.3.1-5)] on linux
</span></span><span class="line"><span class="cl">Type &#34;help&#34;, &#34;copyright&#34;, &#34;credits&#34; or &#34;license&#34; for more information.
</span></span><span class="line"><span class="cl">&gt;&gt;&gt; 
</span></span><span class="line"><span class="cl">&gt;&gt;&gt; import cli
</span></span><span class="line"><span class="cl">&gt;&gt;&gt; status = cli.execute(&#34;write memory&#34;)
</span></span><span class="line"><span class="cl">&gt;&gt;&gt; if &#34;OK&#34; in status: print(&#34;Device configuration was saved!&#34;)
</span></span><span class="line"><span class="cl">...
</span></span><span class="line"><span class="cl">Device configuration was saved!
</span></span></code></pre></div><p>The example above uses the <strong>cli.execute</strong> Python function, which will run commands in Cisco&rsquo;s exec mode.</p>
<p>What if we wanted to make configuration changes? In that case we would use the <strong>cli.configure</strong> function:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">&gt;&gt;&gt; config_data = &#34;&#34;&#34;interface loopback200
</span></span><span class="line"><span class="cl">... ip address 172.16.99.10 255.255.255.0
</span></span><span class="line"><span class="cl">... &#34;&#34;&#34;
</span></span><span class="line"><span class="cl">&gt;&gt;&gt;
</span></span><span class="line"><span class="cl">&gt;&gt;&gt; cli.configure(config_data)
</span></span><span class="line"><span class="cl">&#39;Line 1 SUCCESS:  interface loopback200\nLine 2 SUCCESS:  ip address 172.16.99.10 255.255.255.0\n&#39;
</span></span><span class="line"><span class="cl">&gt;&gt;&gt;
</span></span><span class="line"><span class="cl">&gt;&gt;&gt; cli.execute(&#34;show run interface loopback200&#34;)
</span></span><span class="line"><span class="cl">&#39;Building configuration...\nCurrent configuration : 68 bytes\n!\ninterface Loopback200\n ip address 172.16.99.10 255.255.255.0\nend\n&#39;
</span></span></code></pre></div><p>In the above example, we used a multi-line comment to provide the list of commands to enter. The <strong>cli.configure</strong> function also supports a Python list - so we could provide the commands in that format as well.</p>
<p>You&rsquo;ll notice that the Python interpreter returns a status for each command that we attempted to run. This should allow us to error-check &amp; ensure that all of our intended configuration was accepted.</p>
<p>Lastly, we used the <strong>cli.execute</strong> command again to validate that our running configuration looks correct.</p>
<p>There&rsquo;s a bit more functionality built into the <strong>cli</strong> Python module, but I just wanted to cover some of the common use cases. More details can be found <a href="https://www.cisco.com/c/en/us/td/docs/ios-xml/ios/prog/configuration/1610/b_1610_programmability_cg/python_api.html">here</a></p>
<hr>
<h2 id="a-few-common-questions">A Few Common Questions</h2>
<p><strong>Does this give me access to the underlying IOS-XE Linux shell?</strong></p>
<p>Nope, anything running in guestshell is running in a container - which runs <em>on-top</em> of the IOS-XE image.</p>
<p><strong>What about resource conflicts?</strong></p>
<p>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.</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
