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!

About Brian McGahan, CCIE #8593, CCDE #2013::13:

Brian McGahan was one of the youngest engineers in the world to obtain the CCIE, having achieved his first CCIE in Routing & Switching at the age of 20 in 2002. Brian has been teaching and developing CCIE training courses for over 10 years, and has assisted thousands of engineers in obtaining their CCIE certification. When not teaching or developing new products Brian consults with large ISPs and enterprise customers in the midwest region of the United States.

Find all posts by Brian McGahan, CCIE #8593, CCDE #2013::13 | Visit Website


You can leave a response, or trackback from your own site.

13 Responses to “IOS Random IPv4 & IPv6 Route Generator in TCL”

 
  1. Paul Lampron says:

    Not bad a someone who doesn’t use TCL usually :-P

  2. Butch Deadlift says:

    Why didn’t you just lower the MTU of the physical interface to force the fragmentation issue?

  3. Jason Cook says:

    Was able to get it to work re-iterating with this:

    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]
    # ****NEWVAR****
    set m 0

    # 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 $LOOBACK_NUMBER
    set LOOPBACK_NUMBER [expr 10000 + $n]

    # send IOS exec commands ***NEWCODE
    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" ]
    foreach LINE [split $OUTPUT "\n"] {
    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 { [expr $m==1] } {
    incr n -1 }
    }
    # END NEWCODE

    }

    }

  4. Jason Cook says:

    With comments to make it a bit less perl-like… ;)
    ————

    # send IOS exec commands ***NEWCODE
    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 }
    }

    # END NEWCODE

  5. Alessio says:

    That’s great! Thanks to both of you!

  6. Craig says:

    I’m not a TCL writer, but I copied and expanded the same concept into VRF’s. This will do the same random Loopback generation, but also generate VRF’s, and create the associated BGP VRF process, then randomly assign the Loopbacks to VRF’s:

    Use:
    1) Create a BGP process (any ASN)
    2) Paste in the TCL script
    3) Run the TCL script with 2 variables, first is the number of VRF’s, second is the number of Loopbacks (‘generate_vrfs 10 100′ would create 10 VRF’s and 100 loopbacks)

    Enjoy!

    proc generate_vrfs {x z} {

    # 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

    # set $BGP
    set BGP [exec "show run | in router.bgp"]

    # Iterate the loop $x times

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

    # set $VRF_NUMBER
    set VRF_NUMBER [expr 65000 + $n]

    # send IOS exec commands
    set OUTPUT [ ios_config "ip vrf $VRF_NUMBER" "rd $VRF_NUMBER:$VRF_NUMBER" "route-target both $VRF_NUMBER:$VRF_NUMBER" ]

    # send IOS exec commands
    set OUTPUT [ ios_config "$BGP" "address-family ipv4 vrf $VRF_NUMBER" "redistribute connected" ]

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

    }

    }

    for {set g 1} {$g<=$z} {incr g 1} {

    # generate random $VRF assignment
    set VRF_RANGE [rand_range 1 $x]
    set VRF [expr 65000 + $VRF_RANGE]

    # 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]

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

    # send IOS exec commands
    set OUTPUT [ ios_config "interface Loopback$LOOPBACK_NUMBER" "ip vrf forwarding $VRF" "ip address $a.$b.$c.$d $len($y)" ]

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

    }

    }

    }

  7. Martijn Smit says:

    Awesome script Brian! Was just looking for some randomiser for some routing prefixes.

    I’m working with Nexus devices, and it seems the script needs a few adjustments for it to work on NX-OS. Looks like there’s no ios_config, or nxos_config on NX-OS, plus the loopback numbers are limited (at least on the code I’m working on)

    If anyone’s interested, here’s the diff:

    — tclsh_ios_random_loopbacks.tcl 2014-05-07 23:03:32.000000000 +0200
    +++ tclsh_nxos_random_loopbacks.tcl 2014-05-07 23:04:21.000000000 +0200
    @@ -37,6 +37,9 @@ proc generate_loopbacks {x} {
    set len(31) 255.255.255.254
    set len(32) 255.255.255.255

    + # NX-OS requires entering config mode
    + cli configure terminal
    +
    # Iterate the loop $x times

    for {set n 1} {$n<=$x} {incr n 1} {
    @@ -66,10 +69,12 @@ proc generate_loopbacks {x} {
    set m 0

    # set $LOOBACK_NUMBER
    - set LOOPBACK_NUMBER [expr 10000 + $n]
    + set LOOPBACK_NUMBER [expr 10 + $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" ]
    + # send NX-OS exec commands
    + set OUTPUT [ cli interface Loopback$LOOPBACK_NUMBER ]
    + lappend OUTPUT [ cli ip address $a.$b.$c.$d $len($y) ]
    + lappend OUTPUT [ cli ipv6 address 2001:$e:$f:$g:$h:$i:$j:$k/$z ]

  8. Jason Cook says:

    A couple of nice additions here. I was fiddling around with this in order to add random AS path and community data to the random prefixes created. So I extended the script above to create a number of prefix lists (I used the variable w below, so you will get $w ipv4 prefix lists and $w ipv6 prefix lists) and then two route-maps (SET_IPV4_RANDOM_ATTR and SET_IPV6_RANDOM_ATTR) that have as many sections as there are prefix lists, and in those statements, match the prefix lists and set a random as-path prepend and set of communities.

    If you want there is commented out code to set a specific as-path and/or set of communities for one of the many iterations (to give yourself something specific to search against for further down the line).

    The script is called by pasting it in and then typing in “proc generate_loopbacks ”

    Once it completed you will need to redistribute connected and then apply the route-maps outbound to a bgp peer or peers.

    Also, depending on platform the script is long enough it might require being pasted in sections!

    ————–

    proc generate_loopbacks {x w} {

    # 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]
    set m 0

    # 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 $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" ]
    foreach LINE [split $OUTPUT "\n"] {
    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 { [expr $m==1] } {
    incr n -1 }
    }

    if { [expr $m==0] } {

    # Build 'w' number of prefix lists for matching later in route-map
    set FULLRANGE [expr 1 + $w]
    set PREFIX_LIST_NUM [rand_range 1 $FULLRANGE]
    puts [ ios_config "ip prefix-list RAND_IP_PRFX$PREFIX_LIST_NUM permit $a.$b.$c.$d/$y" ]
    puts [ ios_config "ipv6 prefix-list RAND_IP6_PRFX$PREFIX_LIST_NUM permit 2001:$e:$f:$g:$h:$i:$j:$k/$z" ]
    } else {
    puts [ ios_config "interface Loopback$LOOPBACK_NUMBER" "no ipv6 address 2001:$e:$f:$g:$h:$i:$j:$k/$z" ]
    }
    }

    # Create route-map
    for {set o 1} {$o<=$w} {incr o 1} {
    # change the upper value to one more then the desired max as path length
    set AS_PATH_LENGTH [rand_range 1 8]
    # change the upper value to one more then the desired max number of communities per prefix
    set NUMBER_COMMS [rand_range 0 6]
    set ROUTE_MAP_NUM [expr 10 * $o]
    set AS_PATH " "
    set COMMUNITIES " "

    # Create AS_PATH
    for {set p 1} {$p<=$AS_PATH_LENGTH} {incr p 1} {
    #Uncomment the below if you want a specific AS path prepend for one portion of the route-map
    # if {$p==3} {
    #Replace the below line with the desired AS path
    # set AS_PATH "100 200 300 400"
    # }
    # else {
    set TEMP_AS [rand_range 1 64512]
    append AS_PATH " "
    append AS_PATH $TEMP_AS
    # Uncomment below if doing the specific setting of as prepend
    # }
    }

    # Create Community List
    for {set q 1} {$q<=$NUMBER_COMMS} {incr q 1} {
    #Uncomment the below if you want a specific set of communities for one portion of the route-map
    # if {$q==3} {
    #Replace the below line with the desired set of communities
    # set COMMUNITIES "100:100 200:200 300:300"
    # }
    # else {
    set TEMP_COMM " "
    set COMMUNITYA [rand_range 1 65535]
    set COMMUNITYB [rand_range 1 65535]
    append TEMP_COMM $COMMUNITYA
    append TEMP_COMM ":"
    append TEMP_COMM $COMMUNITYB
    append COMMUNITIES " "
    append COMMUNITIES $TEMP_COMM
    # Uncomment below if doing the specific setting of communities
    # }
    }

    puts [ ios_config "route-map SET_IPV4_RANDOM_ATTR permit $ROUTE_MAP_NUM" "match ip address prefix-list RAND_IP_PRFX$o" ]
    puts [ ios_config "route-map SET_IPV4_RANDOM_ATTR permit $ROUTE_MAP_NUM" "set as-path prepend $AS_PATH" ]
    puts [ ios_config "route-map SET_IPV4_RANDOM_ATTR permit $ROUTE_MAP_NUM" "set community $COMMUNITIES" ]
    puts [ ios_config "route-map SET_IPV6_RANDOM_ATTR permit $ROUTE_MAP_NUM" "match ipv6 address prefix-list RAND_IP6_PRFX$o" ]
    puts [ ios_config "route-map SET_IPV6_RANDOM_ATTR permit $ROUTE_MAP_NUM" "set as-path prepend $AS_PATH" ]
    puts [ ios_config "route-map SET_IPV6_RANDOM_ATTR permit $ROUTE_MAP_NUM" "set community $COMMUNITIES" ]
    }
    }

  9. Sergey says:

    A brilliant post! I have tried to solve a task of emulating a large number of BGP routes. I used powershell scripts. My script however gives you matching network statement for BGP, so the origin code is reported as “i” instead of “?” :)

    cls
    $bgp = @()
    $firstoctet = @(0)*(116+96)
    0..115 | % { $firstoctet[$_] = $_ + 11 }
    116..211 | % { $firstoctet[$_] = $_ + 12 }

    $powers= @(0,128,64,32,16,8,4,2,1)
    $BGPNETWORKS=@(“”)
    $bgpmasks=@(“”)

    $mask = @(0)*5

    $address = @(0)*5

    function get-mask($number) {
    if ($number -lt $changeoctet) { return(255) }
    if ($number -eq $changeoctet) {
    $value = 0
    0..$changeshift | % { $value = $value + $powers[$_]}

    return($value)
    }
    if ($number -gt $changeoctet) {return(0)}
    }

    function get-octet($number) {

    if ($number -lt $changeoctet) { return(get-random $firstoctet) }
    if ($number -eq $changeoctet) {
    if ($changeshift -eq 0) { return(1) }
    $network = (Get-Random -Minimum 0 -Maximum $changeshift)
    0..$network | % {
    $subnet = $subnet + $powers[$_]
    }

    return($subnet+1)
    }
    if ($number -gt $changeoctet) { return(1) }
    }

    $counter = read-host “Enter number of loopbacks”
    [int]$step = read-host “Enter the start number”
    $asnumber = read-host “Enter the AS number”
    cls

    1..$counter | % {

    $masklength = Get-Random -Minimum 8 -Maximum 30
    $changeoctet = ($masklength – ($masklength % 8)) / 8 + 1
    $changeshift = $masklength % 8

    $mask = $null
    $mask = @(0)*5
    $address = $null
    $address = @(0)*5

    1..4 | % { $mask[$_] = get-mask($_) }
    1..4 | % { $address[$_] = get-octet($_) }
    $bgpnet = @(0)*5
    1..4 | % {
    if ($_ -lt $changeoctet) { $bgpnet[$_] = $address[$_] }
    if ($_ -eq $changeoctet) { $bgpnet[$_] = ($address[$_]-1)}
    if ($_ -gt $changeoctet) { $bgpnet[$_] = $mask[$_] }
    }
    $bgp=”"
    $bgp = [string]$bgpnet[1]+”.”+[string]$bgpnet[2]+”.”+[string]$bgpnet[3]+”.”+[string]$bgpnet[4]+” “+”mask “+[string]$mask[1]+”.”+[string]$mask[2]+”.”+[string]$mask[3]+”.”+[string]$mask[4]+”`n”
    $BGPNETWORKS = $BGPNETWORKS + $bgp

    write-host “interface loop$step ”
    write-host “ip address ” -NoNewline
    write-host $address[1] -NoNewline
    write-host “.” -NoNewline
    write-host $address[2] -NoNewline
    write-host “.” -NoNewline
    write-host $address[3] -NoNewline
    write-host “.” -NoNewline
    write-host $address[4] -NoNewline
    write-host ” ” -NoNewline
    write-host $mask[1] -NoNewline
    write-host “.” -NoNewline
    write-host $mask[2] -NoNewline
    write-host “.” -NoNewline
    Write-Host $mask[3] -NoNewline
    write-host “.” -NoNewline
    Write-Host $mask[4]
    [int]$step = $step+1
    }
    write-host
    write-host “router bgp $asnumber”
    1..$counter | % {
    write-host “network” $bgpnetworks[$_] -NoNewline
    }

  10. Ethan M says:

    Very cool! It works well, but I tried it in GNS3 using the 7200 VXR’s, it ends up erroring out; however, the 3725 emulation works as advertised.

 

Leave a Reply

Categories

CCIE Bloggers