blog
    IOS Random IPv4 & IPv6 Ro ...
    05 May 14

    IOS Random IPv4 & IPv6 Route Generator in TCL

    Posted byBrian McGahan
    facebooktwitterlinkedin
    news-featured

    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!

    Hey! Don’t miss anything - subscribe to our newsletter!

    © 2022 INE. All Rights Reserved. All logos, trademarks and registered trademarks are the property of their respective owners.
    instagram Logofacebook Logotwitter Logolinkedin Logoyoutube Logo