Thursday 19 August 2010

Learning about tclsh

On groupstudy someone was asking about how to show all of the route-targets associated with the BGP routes.  I have wondered what nice command would do that myself - it's easy enough to get the route-distinguishers (show ip bgp vpnv4 all) and it is possible to find the route-target for individual prefixes (show ip bgp vpnv4 all prefix/length) but no easy way to quickly get a list of all RTs.

Since we know how to do it manually, the obvious way is to script something up.  TCL (Tool Command Language) is a scripting language that is available on IOS platforms.  The most common TCL script for CCIE candidates appears to of the "ping all your routers" variety which is very helpful in quickly validating connectivity.

The get_rt script is fairly simple but took me a little while to get used to how the syntax and string matching capabilities work.  TCL Tutor is a fantastic tutoring application for the language that as well as describing how things work in individual lessons, also has an interpreter built in with example code that you can modify and run directly.

Below is get_rt:
proc get_rt {} {
    set cmdout [exec "sh ip bgp vpnv4 all | include ^\\*"]
    foreach line [split $cmdout "\n"] {
       if [regexp {([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\/[0-9]+)} $line prefix] {
          puts [exec "sh ip bgp vpnv4 all $prefix \| include BGP\|RT"]
       }
    }
}
What the lines are doing

  1. proc get_rt {} {
      defines the name of the procedure
  2. set cmdout [exec "sh ip bgp vpnv4 all | include ^\\*"]
       is the same as typing "sh ip bgp vpnv4 all | include ^\*" and assigning the output to a variable called cmdout.  The regular expression means we match only lines that start with a * (in other words we're only caring about valid routes)
  3. foreach line [split $cmdout "\n"] {
       we're starting a loop which takes each line of output from cmdout and temporarily assigning that to a variable called line
  4. if [regexp {([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\/[0-9+)} $line prefix] {
       the regular expression is attempting matching an ip prefix in the form of a.b.c.d/l in the variable line, and if there is a match, the resulting match is placed into a variable called prefix and the following line is executed
  5. puts [exec "sh ip bgp vpnv4 all $prefix \| include BGP\|RT"]
       displays the output of "show ip bgp vpnv4 all a.b.c.d/l | include BGP|RT" to the output
  6. }
       closes the if evaluation on line 4
  7. }
       ends the loop statement and returns for the next line of evaluation from cmdout in line 3 otherwise if all lines have been processed continue down
  8. }
       closes the procedure definition

So how do you apply and execute it?

In this example R1 is set up with some MP-BGP ipv4 routes, so we can actually get some output:

R1#tclsh
R1(tcl)#proc get_rt {} {
+>(tcl)#set cmdout [exec "sh ip bgp vpnv4 all | include ^\\*"]
+>(tcl)#foreach line [split $cmdout "\n"] {
+>(tcl)#if [regexp {([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\/[0-9]+)} $line prefix] {
+>(tcl)#puts [exec "sh ip bgp vpnv4 all $prefix \| include BGP\|RT"]
+>(tcl)#}
+>(tcl)#}
+>(tcl)#}

R1(tcl)#get_rt
BGP routing table entry for 64512:10:1.2.3.0/24, version 6
      Extended Community: RT:64512:10

BGP routing table entry for 64512:10:4.3.2.0/25, version 7
      Extended Community: RT:64512:10

BGP routing table entry for 64512:20:2.4.0.0/16, version 8
      Extended Community: RT:64512:20

BGP routing table entry for 64512:20:8.6.4.2/32, version 9
      Extended Community: RT:64512:20
R1(tcl)#


So there you go.  Hopefully this can be used as a simple base for various lumping together commands to get something useful.

As a closing note here, depending on the characters you directly want to use in your strings, you need to escape them for TCL itself not think there is a directive made towards it

No comments:

Post a Comment