NXOS – Bash scripting at the CLI

NXOS – Bash scripting at the CLI

Every now and again you see a snippet of complex CLI syntax that gives you pause for thought. Last week I saw the command below in a change procedure. The command was being used to verify baseline BGP neighbor state and re-verify after a policy change.

1
2
3
show ip bgp peer-template eBGP_Peers | egrep default | sed 's/default://'  \
| tr -s '  |\n' | tr -s ' ' '\n' | sed 's/^/show ip bgp nei /' \
| sed 's/$/ adver | grep \//' | vsh

I was a little daunted by the complexity of the command at first. I was slightly embarrassed too, as I had no idea what the command did. I learned that this command finds all neighbors which use a named bgp peer-template, and lists the prefixes they advertise. In this post I’ll break down the command and share the love about NXOS CLI and bash scripting.

Lab Configuration

For some context, I’ve added my simplified and sanitised example NXOS configuration below. It shows an IPv4 unicast BGP configuration with a peer-template definition and individual neighbors inheriting that configuration. All four adjacencies will advertise the same 50.50.50.0/24 prefix. I won’t bore you with the config for the peer routers.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
NXOS-r2# sh running-config bgp
feature bgp
ip route 50.50.50.0/24 Null0  !BGP prefix origination
route-map ebgp-outbound permit 0
router bgp 65001
  address-family ipv4 unicast
  template peer eBGP_Peers
    description eBGP to transit providers
    address-family ipv4 unicast
      route-map ebgp-inbound in
      route-map ebgp-outbound out
      next-hop-self
      soft-reconfiguration inbound
      network 50.50.50.0 mask 255.255.255.0
  neighbor 10.0.1.1 remote-as 65501
    inherit peer eBGP_Peers
    description TransitProvider_1
  neighbor 10.0.2.2 remote-as 65502
    inherit peer eBGP_Peers
    description TransitProvider_2
    no shutdown
  neighbor 10.0.3.3 remote-as 65503
    inherit peer eBGP_Peers
    description TransitProvider_3
    no shutdown
  neighbor 10.0.4.4 remote-as 65504
    inherit peer eBGP_Peers
    description TransitProvider_4
    no shutdown

Break it down

Of course you have the option to just ‘copy and paste’ the command without fully understanding it. If you need to do that then.. ‘okay’. But you’ll always be at the mercy of google if you approach networking that way. I had to strip the command back to it’s core and rebuild it, examining the output at each stage, before I understood what was happening.
Heres the first command output with no refinements. The last line is the one we’re interested in, with a list of all ‘members’ of the peer template:

1
2
3
4
5
6
7
8
9
10
11
NXOS-r1# sh ip bgp peer-template eBGP_Peers
BGP peer-template is eBGP_Peers
  Description: eBGP to transit providers
  For address family: IPv4 Unicast
  Inbound soft reconfiguration allowed
  Nexthop always set to local peering address, 0.0.0.0
  Third-party Nexthop will not be computed.
  Inbound route-map configured is ebgp-inbound
  Outbound route-map configured is ebgp-outbound
Members of peer-template eBGP_Peers:
default:10.0.1.1       10.0.2.2       10.0.3.3       10.0.4.4

We grep for the ‘default:’ string as it only appears on the line we need.

1
2
show ip bgp peer-template eBGP_Peers | egrep default
default:10.0.1.1       10.0.2.2       10.0.3.3       10.0.4.4

But we only want neighbor IP addresses, so we use sed to replace ‘default:’ with ”. In other words we remove that string.

1
2
show ip bgp peer-template eBGP_Peers | egrep default | sed 's/default://'
10.0.1.1       10.0.2.2       10.0.3.3       10.0.4.4

The next step is to ‘squeeze’ any spaces or newlines (\n) by replacing them with a single space. The tr -s command does a translate and squeeze. The command is nicely named as you can see from the compressed output below.

1
2
3
show ip bgp peer-template eBGP_Peers | egrep default | sed 's/default://' \
| tr -s '  |\n'
10.0.1.1 10.0.2.2 10.0.3.3 10.0.4.4

We’ll need to have a separate command for each of these neighbors to show the bgp neighbor related output. I love the way this is achieved, replacing each space with a newline. No need for ‘for’ or ‘while’ loops here.

1
2
3
4
5
6
show ip bgp peer-template eBGP_Peers | egrep default | sed 's/default://' \
| tr -s '  |\n' | tr -s ' ' '\n'
10.0.1.1
10.0.2.2
10.0.3.3
10.0.4.4

Now the hard work has been done, you prepend each neighbor address with a ‘show ip bgp nei’ command. This is done by replacing the start of line character ‘^’ with the string.

1
2
3
4
5
6
show ip bgp peer-template eBGP_Peers | egrep default | sed 's/default://' \
| tr -s '  |\n' | tr -s ' ' '\n' | sed 's/^/show ip bgp nei /'
show ip bgp nei 10.0.1.1
show ip bgp nei 10.0.2.2
show ip bgp nei 10.0.3.3
show ip bgp nei 10.0.4.4

Next you append the required arguments to get the advertised routes and grep for a ‘/’ to pull the prefixes from the output. This time we replace the end of line character ‘$’ with the desired string. Beware that the ‘|’ symbol after ‘adver’ is part of the sed replacement string. The ‘\//’ is also bit odd looking. Here the first ‘\’ is escaping the adjacent ‘/’ so that we actually grep for this character. The last ‘/’ tells sed that the replacement string is complete.

1
2
3
4
5
6
7
show ip bgp peer-template eBGP_Peers | egrep default | sed 's/default://' \
| tr -s '  |\n' | tr -s ' ' '\n' | sed 's/^/show ip bgp nei /' \
| sed 's/$/ adver | grep \//'
show ip bgp nei 10.0.1.1 adver | grep /
show ip bgp nei 10.0.2.2 adver | grep /
show ip bgp nei 10.0.3.3 adver | grep /
show ip bgp nei 10.0.4.4 adver | grep /

If you were expecting to see some bgp output after these commands then you’re not alone. However the the CLI parser treats these commands as display output rather than command inputs. If you want these commands to be interpreted and acted upon you need the ‘vsh’ command. Thankfully it’s pretty easy to use.

1
2
3
4
5
6
7
show ip bgp peer-template eBGP_Peers | egrep default | sed 's/default://' \
| tr -s '  |\n' | tr -s ' ' '\n' | sed 's/^/show ip bgp nei /' \
| sed 's/$/ adver | grep \//' | vsh
l50.50.50.0/24 0.0.0.0 100 32768 i
l50.50.50.0/24 0.0.0.0 100 32768 i
l50.50.50.0/24 0.0.0.0 100 32768 i
l50.50.50.0/24 0.0.0.0 100 32768 i

And so you have it. If you just wanted a count of the prefixes you could pipe it into a count function or a file for later comparison.

Analysis

I love to learn from others work, and wish I could properly attribute it. I also have no doubt that there are more efficient ways of gathering this output, so I’d love to see your improvements in the comments to that I can learn from you too. The bash stalwart tools like egrep, sed, cut, tr, wc and uniq will always be useful. Having access to all of these and the pipe command to tie them together is pretty sweet.
I love simplicity so, in theory, I should hate commands like this. Why not have a series of individual commands pulled from the configuration by eye, instead of this monstrous command? Well, the joy of commands like this is that I don’t need to know the number of peers nor their IP addresses in advance of issuing the command. Therefore the command is easy to re-use.  Also I don’t need to rely upon a human scraping the initial list of neighbors or doing a copy and paste for different routers. In my opinion, having humans editing verification commands introduces more fragility than the complex syntax presented here.
As always I’d love to hear your views in the comments.

4 thoughts on “NXOS – Bash scripting at the CLI

  1. Wow, fun article. Thanks for sharing! Frankly, I’m always extremely cautious about what I type into a production 7010 – especially long strings like that. If that thing showed up on my door step and I did not have a DEV VDC, then I’d freak.

    1. Hey Will,
      Fair point. I was able to break out the post using a lab Nx3064. Hopefully in the future the VIRL version of titanium for NXOS will de-risk these commands. In the mean time, all of the stages above should be safe from the command line until to get to ‘vsh’ at the end. Even then it’s just a show second show command.
      Thanks for the comment,
      John H

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.