Jun
26

In a recent post I talked about Using Config Replace For Managing Router & Switch Initial Configs.  This is a great feature that can be useful to quickly switch between initial configs and a default config while labbing on your routers without having to write erase and reload - which can be very time consuming.  However, I previously assumed that this required a staged "blank" config in the router's flash, because regular IOS and IOS-XE don't have a built in text editor such as vi/nano/pico that would let you create a blank file on the router's flash.

Thanks to my buddy xous in #cisco on irc.freenode.net, I found that you can use TCL to write a file to flash through the IOS CLI, the same as if it was a native text editor.  The end result is that you can use the following code to write a blank config file at any time to rollback to.

tclsh
puts [ open "flash:blank.cfg" w+] {
version 15.4
!
end
}
tclquit

An example implementation of this is as follows:

R1#show ip int brief | exclude unassign
Interface IP-Address OK? Method Status Protocol
GigabitEthernet1.13 155.1.13.1 YES TFTP up up
GigabitEthernet1.100 169.254.100.1 YES TFTP up up
GigabitEthernet1.146 155.1.146.1 YES TFTP up up
Loopback0 150.1.1.1 YES TFTP up up
Tunnel0 155.1.0.1 YES TFTP up up

R1#tclsh
R1(tcl)#puts [ open "flash:blank.cfg" w+] {
+>(tcl)#version 1.1
+>(tcl)#!
+>(tcl)#end
+>(tcl)#}
R1(tcl)#tclquit
R1#config replace flash:blank.cfg
This will apply all necessary additions and deletions
to replace the current running configuration with the
contents of the specified configuration file, which is
assumed to be a complete configuration, not a partial
configuration. Enter Y if you are sure you want to proceed. ? [no]: yes
Overwriting with a file sized 50% or less than running config's. Proceed? [no]: yes
% Be sure to ask the CA administrator to revoke your certificates.

*snip*

Router#
Router#show ip int brief | ex unassign
Interface IP-Address OK? Method Status Protocol

Router#

The end result is that you can at any time default the router's config without having to erase and reload. Note that there are certain caveats such as deleted subinterfaces on Ethernet or Serial links which will still exist as "deleted" in the running config, but in most cases for our applications this will not be an issue.

Also as a shameless plug for IRC feel free to join the discussion in the channel #cisco on irc.freenode.net and chat with us. You can find me there with nick bmcgahan.

Happy labbing!

May
05

This weekend while working on content updates for CCIE R&S Version 5, I ran into an interesting problem.  In order to test some nuances of routing protocol updates and packet fragmentation, I was trying to generate BGP UPDATE messages that would exceed the transit MTU.  To do this I manually created a bunch of Loopback interfaces and did a redistribute connected into BGP.  When I looked at the packet capture details, I started to realize how many routes I'd actually need in order to fill up the packet sizes.  After wasting about 30 minutes copying and pasting new Loopbacks over and over, I decided to come up with a better automated solution instead.  I thought, “why not just have the router generate its own random Loopback addresses and then advertise them into BGP?” Well surprisingly I actually got it to work, despite my amateur at best coding skills.

The following TCL script is used to generate a given number of Loopback interfaces with random IPv4 and IPv6 addresses.  To use it simply start the tclsh from the IOS CLI, paste the procedure in, then invoke it with generate_loopbacks X, where “X” is the number of routes you want to generate.  Note that I didn’t add any error checking for overlapping addresses or invalid address and mask combinations.  If someone wants to update the script to account for this, please feel free to do so and I’ll throw 100 rack rental tokens your way for the trouble. Edit: Special thanks to Jason Cook for adding the error checking for me.

A quick demo of the script in action can be found after the jump.

The script:

proc generate_loopbacks {x} {

# random number generator
proc rand_range { min max } { return [expr int(rand() * ($max - $min)) + $min] }

# define subnet mask lengths
set len(1) 128.0.0.0
set len(2) 192.0.0.0
set len(3) 224.0.0.0
set len(4) 240.0.0.0
set len(5) 248.0.0.0
set len(6) 252.0.0.0
set len(7) 254.0.0.0
set len(8) 255.0.0.0
set len(9) 255.128.0.0
set len(10) 255.192.0.0
set len(11) 255.224.0.0
set len(12) 255.240.0.0
set len(13) 255.248.0.0
set len(14) 255.252.0.0
set len(15) 255.254.0.0
set len(16) 255.255.0.0
set len(17) 255.255.128.0
set len(18) 255.255.192.0
set len(19) 255.255.224.0
set len(20) 255.255.240.0
set len(21) 255.255.248.0
set len(22) 255.255.252.0
set len(23) 255.255.254.0
set len(24) 255.255.255.0
set len(25) 255.255.255.128
set len(26) 255.255.255.192
set len(27) 255.255.255.224
set len(28) 255.255.255.240
set len(29) 255.255.255.248
set len(30) 255.255.255.252
set len(31) 255.255.255.254
set len(32) 255.255.255.255

# Iterate the loop $x times

for {set n 1} {$n<=$x} {incr n 1} {

# generate random IPv4 address
set a [rand_range 1 223]
set b [rand_range 1 255]
set c [rand_range 1 255]
set d [rand_range 1 255]

# generate random IPv4 mask
set y [rand_range 1 32]

# generate random IPv6 address
set e [format %x [rand_range 1 65534]]
set f [format %x [rand_range 1 65534]]
set g [format %x [rand_range 1 65534]]
set h [format %x [rand_range 1 65534]]
set i [format %x [rand_range 1 65534]]
set j [format %x [rand_range 1 65534]]
set k [format %x [rand_range 1 65534]]

# generate random IPv6 mask
set z [rand_range 16 64]

# set error check variable
set m 0

# set $LOOBACK_NUMBER
set LOOPBACK_NUMBER [expr 10000 + $n]

# send IOS exec commands
set OUTPUT [ ios_config "interface Loopback$LOOPBACK_NUMBER" "ip address $a.$b.$c.$d $len($y)" "ipv6 address 2001:$e:$f:$g:$h:$i:$j:$k/$z" ]

# Split the OUTPUT variable into individual lines, and for each line place it into the variable LINE
foreach LINE [split $OUTPUT "\n"] {

# check if the LINE variable contains an indication that there is a problem with a random address
# and if so, set a variable m to a specific value
if { [regexp "is overlapping with" $LINE] } {
set m 1 } elseif { [regexp "overlaps with" $LINE] } {
set m 1 } elseif { [regexp "Bad mask" $LINE] } {
set m 1 }

# if the variable m is 1 decrement the variable n used to control the for loop by 1
# forcing the most recent loopback to be re-iterated by the above script
if { [expr $m==1] } {
incr n -1 }
}

}

}

Below is a basic demo of the script in action. R1 and R2 are directly connected on the IPv4 network 10.0.0.0/24 and the IPv6 network 2001::/64. They are peering EBGP, and R1 is doing redistribute connected into BGP in both IPv4 Unicast and IPv6 Unicast address families.

R1#show ip int brief Interface              IP-Address      OK? Method Status                Protocol
GigabitEthernet1 unassigned YES NVRAM up up
GigabitEthernet1.10 10.0.0.1 YES manual up up
GigabitEthernet2 unassigned YES NVRAM administratively down down
GigabitEthernet3 unassigned YES NVRAM administratively down down

R1#show ipv6 int brief GigabitEthernet1 [up/up]
unassigned
GigabitEthernet1.10 [up/up]
FE80::250:56FF:FE8D:4B00
2001::1
GigabitEthernet2 [administratively down/down]
unassigned
GigabitEthernet3 [administratively down/down]
unassigned

R1#sh run | s bgp router bgp 1
bgp log-neighbor-changes
neighbor 10.0.0.2 remote-as 2
neighbor 2001::2 remote-as 2
!
address-family ipv4
redistribute connected
neighbor 10.0.0.2 activate
no neighbor 2001::2 activate
exit-address-family
!
address-family ipv6
redistribute connected
neighbor 2001::2 activate
exit-address-family

R2#sh bgp ipv4 unicast summary BGP router identifier 10.0.0.2, local AS number 2
BGP table version is 144, main routing table version 144
1 network entries using 248 bytes of memory
1 path entries using 120 bytes of memory
1/1 BGP path/bestpath attribute entries using 240 bytes of memory
1 BGP AS-PATH entries using 24 bytes of memory
0 BGP route-map cache entries using 0 bytes of memory
0 BGP filter-list cache entries using 0 bytes of memory
BGP using 632 total bytes of memory
BGP activity 74/72 prefixes, 74/72 paths, scan interval 60 secs

Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd
10.0.0.1 4 1 22 19 144 0 0 00:13:52 1

R2#sh bgp ipv6 unicast summary BGP router identifier 10.0.0.2, local AS number 2
BGP table version is 4, main routing table version 4
1 network entries using 272 bytes of memory
1 path entries using 144 bytes of memory
1/1 BGP path/bestpath attribute entries using 240 bytes of memory
1 BGP AS-PATH entries using 24 bytes of memory
0 BGP route-map cache entries using 0 bytes of memory
0 BGP filter-list cache entries using 0 bytes of memory
BGP using 680 total bytes of memory
BGP activity 74/72 prefixes, 74/72 paths, scan interval 60 secs

Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd
2001::1 4 1 10 8 4 0 0 00:04:14 1

R2#show bgp ipv4 unicast BGP table version is 144, local router ID is 10.0.0.2
Status codes: s suppressed, d damped, h history, * valid, > best, i - internal,
r RIB-failure, S Stale, m multipath, b backup-path, f RT-Filter,
x best-external, a additional-path, c RIB-compressed,
Origin codes: i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found

Network Next Hop Metric LocPrf Weight Path
r> 10.0.0.0/24 10.0.0.1 0 0 1 ?

R2#show bgp ipv6 unicast BGP table version is 4, local router ID is 10.0.0.2
Status codes: s suppressed, d damped, h history, * valid, > best, i - internal,
r RIB-failure, S Stale, m multipath, b backup-path, f RT-Filter,
x best-external, a additional-path, c RIB-compressed,
Origin codes: i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found

Network Next Hop Metric LocPrf Weight Path
r> 2001::/64 2001::1 0 0 1 ?

From the above output we can see that R2's only BGP routes right now are the directly connected links that R1's redistributing. Now R1 invokes the TCL script:

R1#tclsh
R1(tcl)#proc generate_loopbacks {x} {
+>(tcl)#
+>(tcl)# # random number generator
+>(tcl)# proc rand_range { min max } { return [expr int(rand() * ($max - $min)) + $min] }
+>(tcl)#
+>(tcl)# # define subnet mask lengths
+>(tcl)# set len(1) 128.0.0.0
+>(tcl)# set len(2) 192.0.0.0
+>(tcl)# set len(3) 224.0.0.0
+>(tcl)# set len(4) 240.0.0.0
+>(tcl)# set len(5) 248.0.0.0
+>(tcl)# set len(6) 252.0.0.0
+>(tcl)# set len(7) 254.0.0.0
+>(tcl)# set len(8) 255.0.0.0
+>(tcl)# set len(9) 255.128.0.0
+>(tcl)# set len(10) 255.192.0.0
+>(tcl)# set len(11) 255.224.0.0
+>(tcl)# set len(12) 255.240.0.0
+>(tcl)# set len(13) 255.248.0.0
+>(tcl)# set len(14) 255.252.0.0
+>(tcl)# set len(15) 255.254.0.0
+>(tcl)# set len(16) 255.255.0.0
+>(tcl)# set len(17) 255.255.128.0
+>(tcl)# set len(18) 255.255.192.0
+>(tcl)# set len(19) 255.255.224.0
+>(tcl)# set len(20) 255.255.240.0
+>(tcl)# set len(21) 255.255.248.0
+>(tcl)# set len(22) 255.255.252.0
+>(tcl)# set len(23) 255.255.254.0
+>(tcl)# set len(24) 255.255.255.0
+>(tcl)# set len(25) 255.255.255.128
+>(tcl)# set len(26) 255.255.255.192
+>(tcl)# set len(27) 255.255.255.224
+>(tcl)# set len(28) 255.255.255.240
+>(tcl)# set len(29) 255.255.255.248
+>(tcl)# set len(30) 255.255.255.252
+>(tcl)# set len(31) 255.255.255.254
+>(tcl)# set len(32) 255.255.255.255
+>(tcl)#
+>(tcl)## Iterate the loop $x times
+>(tcl)#
+>(tcl)# for {set n 1} {$n<=$x} {incr n 1} {
+>(tcl)#
+>(tcl)# # generate random IPv4 address
+>(tcl)# set a [rand_range 1 223]
+>(tcl)# set b [rand_range 1 255]
+>(tcl)# set c [rand_range 1 255]
+>(tcl)# set d [rand_range 1 255]
+>(tcl)#
+>(tcl)# # generate random IPv4 mask
+>(tcl)# set y [rand_range 1 32]
+>(tcl)#
+>(tcl)# # generate random IPv6 address
+>(tcl)# set e [format %x [rand_range 1 65534]]
+>(tcl)# set f [format %x [rand_range 1 65534]]
+>(tcl)# set g [format %x [rand_range 1 65534]]
+>(tcl)# set h [format %x [rand_range 1 65534]]
+>(tcl)# set i [format %x [rand_range 1 65534]]
+>(tcl)# set j [format %x [rand_range 1 65534]]
+>(tcl)# set k [format %x [rand_range 1 65534]]
+>(tcl)#
+>(tcl)# # generate random IPv6 mask
+>(tcl)# set z [rand_range 16 64]
+>(tcl)#
+>(tcl)# # set error check variable
+>(tcl)# set m 0
+>(tcl)#
+>(tcl)# # set $LOOBACK_NUMBER
+>(tcl)# set LOOPBACK_NUMBER [expr 10000 + $n]
+>(tcl)#
+>(tcl)# # send IOS exec commands
+>(tcl)# set OUTPUT [ ios_config "interface Loopback$LOOPBACK_NUMBER" "ip address $a.$b.$c.$d $len($y)" "ipv6 address 2001:$e:$f:$g:$h:$i:$j:$k/$z" ]
+>(tcl)#
+>(tcl)# # Split the OUTPUT variable into individual lines, and for each line place it into the variable LINE
+>(tcl)# foreach LINE [split $OUTPUT "\n"] {
+>(tcl)#
+>(tcl)# # check if the LINE variable contains an indication that there is a problem with a random address
+>(tcl)# # and if so, set a variable m to a specific value
+>(tcl)# if { [regexp "is overlapping with" $LINE] } {
+>(tcl)# set m 1 } elseif { [regexp "overlaps with" $LINE] } {
+>(tcl)# set m 1 } elseif { [regexp "Bad mask" $LINE] } {
+>(tcl)# set m 1 }
+>(tcl)#
+>(tcl)# # if the variable m is 1 decrement the variable n used to control the for loop by 1
+>(tcl)# # forcing the most recent loopback to be re-iterated by the above script
+>(tcl)# if { [expr $m==1] } {
+>(tcl)# incr n -1 }
+>(tcl)# }
+>(tcl)#
+>(tcl)# }
+>(tcl)#
+>(tcl)#}
R1(tcl)#
R1(tcl)#generate_loopbacks 100

After a few minutes the script should be done and R1 should be advertising the new routes into BGP:

R2#show bgp ipv4 unicast
BGP table version is 210, local router ID is 10.0.0.2
Status codes: s suppressed, d damped, h history, * valid, > best, i - internal,
r RIB-failure, S Stale, m multipath, b backup-path, f RT-Filter,
x best-external, a additional-path, c RIB-compressed,
Origin codes: i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found

Network Next Hop Metric LocPrf Weight Path
*> 6.95.74.8/31 10.0.0.1 0 0 1 ?
r> 10.0.0.0/24 10.0.0.1 0 0 1 ?
*> 17.48.0.0/12 10.0.0.1 0 0 1 ?
*> 18.96.0.0/12 10.0.0.1 0 0 1 ?
*> 20.149.128.0/19 10.0.0.1 0 0 1 ?
*> 24.128.0.0/12 10.0.0.1 0 0 1 ?
*> 38.223.64.0/23 10.0.0.1 0 0 1 ?
*> 45.250.118.192/26
10.0.0.1 0 0 1 ?
*> 46.43.110.166/31 10.0.0.1 0 0 1 ?
*> 53.29.128.0/17 10.0.0.1 0 0 1 ?
*> 54.192.224.0/20 10.0.0.1 0 0 1 ?
*> 54.198.33.64/26 10.0.0.1 0 0 1 ?
*> 59.137.166.128/27
10.0.0.1 0 0 1 ?
*> 63.218.166.192/26
10.0.0.1 0 0 1 ?
*> 64.0.0.0/4 10.0.0.1 0 0 1 ?
*> 82.10.112.0/20 10.0.0.1 0 0 1 ?
*> 84.223.226.96/27 10.0.0.1 0 0 1 ?
*> 86.129.194.64/27 10.0.0.1 0 0 1 ?
*> 90.91.0.0/18 10.0.0.1 0 0 1 ?
*> 90.176.106.0/23 10.0.0.1 0 0 1 ?
[snip]

R2#show bgp ipv6 unicast
BGP table version is 88, local router ID is 10.0.0.2
Status codes: s suppressed, d damped, h history, * valid, > best, i - internal,
r RIB-failure, S Stale, m multipath, b backup-path, f RT-Filter,
x best-external, a additional-path, c RIB-compressed,
Origin codes: i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found

Network Next Hop Metric LocPrf Weight Path
r> 2001::/64 2001::1 0 0 1 ?
*> 2001:434::/30 2001::1 0 0 1 ?
*> 2001:613:93FF:8B40::/60
2001::1 0 0 1 ?
*> 2001:7E2:8398::/46
2001::1 0 0 1 ?
*> 2001:86D:FA5C:4000::/51
2001::1 0 0 1 ?
*> 2001:8AD:9170::/44
2001::1 0 0 1 ?
*> 2001:136F:E000::/37
2001::1 0 0 1 ?
*> 2001:156A:E238::/49
2001::1 0 0 1 ?
*> 2001:169C::/30 2001::1 0 0 1 ?
*> 2001:192D:B2EC:2548::/61
2001::1 0 0 1 ?
*> 2001:1A00::/23 2001::1 0 0 1 ?
*> 2001:1C00::/23 2001::1 0 0 1 ?
[snip]

Feel free to use and modify the script any way you like!

Jul
08

For a limited time we are publishing the Route Redistribution videos from our CCIE Routing & Switching Advanced Technologies Class for public viewing.  These videos cover all aspects of Route Redistribution needed for the CCIE R&S Lab Exam outside of the scope of MPLS, and will also be useful for any engineers looking for more information on how the Route Redistribution process works.

Specifically these videos cover basic and advanced route redistribution configuration, verification, and troubleshooting, including how and why route redistribution loops occur, how to identify and fix loops related to both Administrative Distance and Metric, TCL scripting for reachability testing, route tagging, the IP Route Profile feature, how to use and interpret the debug ip routing output, and other related topics.  Links the videos are as follows:

For technical questions about the topics covered in these videos please visit INE's Online Community.

All of these videos and others totalling over 80 hours for the CCIE R&S ATC series are included in all of our All Access Pass subscriptions at just $159 per month, along with access to over 900 hours of other training videos that include, but are not limited to:

  • CCNA Routing & Switching
  • CCNA Security
  • CCNA Voice
  • CCNA Wireless
  • CCNP Routing & Switching
  • CCNP Security
  • CCNP Voice
  • CCIE Routing & Switching
  • CCIE Security
  • CCIE Voice
  • CCIE Service Provider
Feb
22

One common problem that causes candidates to fail the CCIE Routing & Switching Lab Exam is the lack of complete IP reachability to various segments used in the network topology. However, due to the short time constraints of the lab exam itself it can be difficult to dedicate enough time to properly verify that reachability exists between all relevant segments. In order to solve this problem two very useful features can be implemented during the lab exam, TCL scripting on the routers and macro scripting on the Catalyst switches.

TCL (Tool Control Language) is a scripting language used extensively by Cisco to facilitate the testing and automating of various functions in the IOS. For example advanced implementations on IOS can go as far as programming a router to send you an email when its interface utilization exceeds the normally defined average. In our case we will be using very basic TCL programming to sequentially run the “ping” command.

Macro scripting on the Catalyst switches is a simple way to define templates of configuration that can be applied globally or to interfaces by issuing a single command. Examples of predefined macros include the “switchport host” command, which enables portfast, sets an interface to access mode, and disabled DTP, and the “auto qos” feature. For our implementation we will be using the macros to run pings commands sequentially.

The first step in configuring a ping script is to collect the IP addresses that will be tested in the topology. There are two simple ways to do this, either through the “show ip interface brief” command or the “show ip alias”. Both of these commands show local IP addresses allocated on the device and any addresses that are being proxied for (i.e. dns proxy or NAT). The “show ip interface brief” output can be filtered through quickly by using the “show ip interface brief | exclude unassigned” command so that only interfaces with IP addresses are listed.

Next we’ll need to copy these addresses into a text editor (i.e. Windows notepad in the CCIE lab exam), and do some basic manipulation. To do so use the column select feature of SecureCRT (the terminal emulator used in the lab exam) by holding down the ALT key and then selecting with your left mouse button. This will minimize the amount of text that we have to sort through. Once you’re done you should have a neat list of addresses in notepad that looks something like this:

192.168.255.1
192.168.255.2
192.168.255.3
192.168.255.4
192.168.255.5
192.168.255.6
192.168.255.7
192.168.255.8
192.168.255.9
192.168.255.10

Next we need to manipulate these addresses for TCL on the routers and macro scripting on the switches. For TCL we are going to define the IP addresses as an array, and then use a “for” loop to run the ping command with the array as its argument. The syntax in IOS 12.4 for this implementation is as follows:

foreach VAR {
192.168.255.1
192.168.255.2
192.168.255.3
192.168.255.4
192.168.255.5
192.168.255.6
192.168.255.7
192.168.255.8
192.168.255.9
192.168.255.10
} { puts [exec "ping $VAR"] }

Specifically we are defining the array “VAR”, which represents the IP addresses, then sending the exec command “ping” with “VAR” as the argument. Now to actually run the script in IOS we first must invoke the TCL shell. This is accomplished with the exec command “tclsh”.

Rack17R1#tclsh
+>

Now paste the script from notepad into the router and it should run the pings:

Rack17R1#tclsh
+>foreach VAR {
+>192.168.255.1
+>192.168.255.2
+>192.168.255.3
+>192.168.255.4
+>192.168.255.5
+>192.168.255.6
+>192.168.255.7
+>192.168.255.8
+>192.168.255.9
+>192.168.255.10
+>} { puts [exec "ping $VAR"] }

Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 192.168.255.1, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 1/2/4 ms

Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 192.168.255.2, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 56/58/60 ms

Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 192.168.255.3, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 84/86/89 ms

Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 192.168.255.4, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 140/147/164 ms

Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 192.168.255.5, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 140/142/144 ms

Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 192.168.255.6, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 56/59/65 ms

Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 192.168.255.7, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 1/2/4 ms

Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 192.168.255.8, timeout is 2 seconds:
.....
Success rate is 0 percent (0/5)

Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 192.168.255.9, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 1/2/4 ms

Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 192.168.255.10, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 56/57/60 ms

Rack17R1(tcl)#

Note that in the above test we can see that the address 192.168.255.8 is unreachable. Once TCL is completed we must now make sure to exit the shell. This can be accomplished with either the “tclquit” command, or simply typing “exit” to leave the exec process. Unless TCL is exited the IOS can have some unexpected behavior, like the below example:

Rack17R1(tcl)#conf t
Enter configuration commands, one per line. End with CNTL/Z.
Rack17R1(config)#route-map TCL_BREAKS_SET_COMMAND

Rack17R1(config-route-map)#set local-preference 100
100
Rack17R1(config-route-map)#end

Rack17R1(tcl)#
*Mar 1 05:45:49.906: %SYS-5-CONFIG_I: Configured from console by console
Rack17R1(tcl)#show run | section route-map
route-map TCL_BREAKS_SET_COMMAND permit 10

Rack17R1(tcl)#tclquit
Rack17R1#conf t
Enter configuration commands, one per line. End with CNTL/Z.
Rack17R1(config)#route-map SET_FIXED_WITH_TCL_EXITED
Rack17R1(config-route-map)#set local-preference 100
Rack17R1(config-route-map)#end
Rack17R1#
*Mar 1 05:46:28.882: %SYS-5-CONFIG_I: Configured from console by console
Rack17R1#show run | section route-map
route-map TCL_BREAKS_SET_COMMAND permit 10
route-map SET_FIXED_WITH_TCL_EXITED permit 10
set local-preference 100

The above output shows that TCL was invoked, then a global route-map named “TCL_BREAKS_SET_COMMAND” was defined. In this route-map the “set” command was issued. However with TCL still running the “set” command is first interpreted by TCL as an attempt to set an environment variable, instead of sent to the exec process itself. The result is that instead of setting local-preference for the purpose of BGP manipulation we are actually creating a variable named “local-preference” that has a value of 100. Once the “tclquit” command is issued we can see that the next route-map, “SET_FIXED_WITH_TCL_EXITED” successfully uses the set command.

Next for macro scripting on the Catalyst switches we will take the same list of IP addresses used before and prefix them with the commands “do ping”. The resulting list in notepad should look like this:

do ping 192.168.255.1
do ping 192.168.255.2
do ping 192.168.255.3
do ping 192.168.255.4
do ping 192.168.255.5
do ping 192.168.255.6
do ping 192.168.255.7
do ping 192.168.255.8
do ping 192.168.255.9
do ping 192.168.255.10

Next we’ll insert these commands as a sequence in a global macro as follows:

Rack17SW1#conf t
Enter configuration commands, one per line. End with CNTL/Z.
Rack17SW1(config)#macro name PING_SCRIPT
Enter macro commands one per line. End with the character '@'.
do ping 192.168.255.1
do ping 192.168.255.2
do ping 192.168.255.3
do ping 192.168.255.4
do ping 192.168.255.5
do ping 192.168.255.6
do ping 192.168.255.7
do ping 192.168.255.8
do ping 192.168.255.9
do ping 192.168.255.10
@
Rack17SW1(config)#

We now have a script named “PING_SCRIPT” that can be run from global configuration. To apply the script use the following syntax:

Rack17SW1(config)#macro global apply PING_SCRIPT

Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 192.168.255.1, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 1/4/9 ms
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 192.168.255.2, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 51/57/59 ms
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 192.168.255.3, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 25/30/34 ms
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 192.168.255.4, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 84/89/101 ms
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 192.168.255.5, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 83/87/93 ms
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 192.168.255.6, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 50/57/59 ms
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 192.168.255.7, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 1/1/1 ms
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 192.168.255.8, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 1/1/1 ms
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 192.168.255.9, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 1/1/1 ms
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 192.168.255.10, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 50/57/59 ms
Rack17SW1(config)#

Once you are proficient in this methodology building both the TCL and macro scripts should only take about 2 – 3 minutes in the lab, with another 5 minutes to run them. The resulting time savings versus running manual pings to all segments, and the resulting information on what is reachable and what is not can be the difference between passing and failing the CCIE lab exam.

Subscribe to INE Blog Updates