Forum Discussion

mihai_178850's avatar
mihai_178850
Icon for Nimbostratus rankNimbostratus
Mar 25, 2015

Disable BGP route adv when pool member < 2

Hi all,

 

 

I just fell on the subject of iCALLs and am trying to get around their ways of functioning.

 

I have 2 F5 in different geo-locations both announcing the same VIPs, albeit the second one with a longer path.

 

What I need to do (or find a way to do) for only one VIP is:

 

- if pool members for it < 2 on the main site

 

- then disable the "Route Advertisement" for that VIP

 

 

Any idea where to start with this?

 

iRULES I have made before and there I knew at least how to see the active pool members but with iCALL I am a bit stuck as to:

 

1) where I analyze the pool members condition

 

2) how I disable the Route Advertisement part (I suppose I will need to run a tmsh command for it in case some "API" call is not already implemented for it)

 

4 Replies

  • Found how to do parts of it:

     

    - based on this https://devcentral.f5.com/wiki/iCall.Disable-Interface-if-Pool-Member-Availability-Drops-Below-Threshold.ashx

     

    - and running this command

     

    modify ltm virtual-address route-advertisement enabled

     

    My only remaining questions would be:

     

    - how do all the VIPs that match a name regexp from the config?

     

    - how do I check if route-adv is already enabled so that I do not run the command to enable/disable it all the time if not needed?

     

  • Maybe the following?

    • route adv. will stop when the VS is down
    • trick is to bring the VS down if < 2 pool member (not standard behaviour: down if all)

    If we create a new "status VS" (with reserved IP, port 80) and apply a similar Irule to it

    when HTTP_REQUEST { 
             if { [active_members ] <= 1 } { 
                         log local0. "not enough members in pool " 
                         HTTP::respond 503
             } 
             else { 
                         log local0. "enough members in pool " 
                         HTTP::respond 200 content "UP"
             } 
             default { 
                         HTTP::respond 503 
                         log local0. "monitor check error" 
             } 
    

    Then we put the pool members to this VS

    We add a HTTP monitor (with specific IP/Port of "status VS") to the original pool and require all monitors to be UP

  • That would not completely work for me as I need to make sure that my BGP daemon stops advertising the VS (which means in fact triggering with the tmsh modify command the route adv as disabled instead of sending an HTTP error to the client).

    Logic view would be:

    If active_pool members(pool_name) < 2  
    then
    get_config - vip from regexp name
    if route_adv (vip_ip) NOT disabled
    set route_adv(vip_ip) = disabled
    else
    get_config - vip from regexp name
    if route_adv(vip_ip) NOT enabled, then route_adv(vip_ip) = enabled
    end
    

    The only part I do not currently know how to do and I am googling for is the way to get all the VIPs from the existing config by matching the names with a regexp.

    Can someone help out with a pointer for that? Also, how can I view what the get config really has (the show running config is the same?)

    Thanks!

  • And here is the script that I have made:

    • the handler calls it and passes parameters to it: pool name for IPv4, pool name for IPv6 (or 0 if none), percentage of members that have to be up
    • the script goes through a pool and counts the members, then sees how many are online / total
    • script then goes through all the virtual addresses and stores in an array those that are mapped to the specified pools

    • if the available members/total < percentage, then loop through the array of VIPs stored previously and if the BGP advertisement is not already disabled, then disable it (this avoids doing the same operation twice but is not necessarily saving significant CPU power or anything; I was just obsessed to do it)

    The optimization possibilities are of course present but this should serve as a nice template for someone wanting to develop on this.

    modify script qlPool_min_members.v1 {
        app-service none
        definition {
            set total 0
            set total_v6 0
            set usable 0
            set usable_v6 0
            set i 0
            set i_v6 0
            set err_pn 1
            set err_dst 1
            set err_adv 1
            populate pool and percent variables with the arguments passed to the script
            foreach var { pni pni_v6 percent } {
                    set $var $EVENT::context($var)
            }
            fetch number of available members in each of the two pools and store also the VIPs for each pool in an array
            foreach obj [tmsh::get_status /ltm pool $pni detail] {
              puts $obj
              foreach member [tmsh::get_field_value $obj members] {
                puts $member
                incr total
                if { [tmsh::get_field_value $member status.availability-state] == "available" && \
                [tmsh::get_field_value $member status.enabled-state] == "enabled" } {
                    incr usable
                }
              }
            }
            if { $pni_v6 != 0 } {
            foreach obj [tmsh::get_status /ltm pool $pni_v6 detail] {
              puts $obj
              foreach member [tmsh::get_field_value $obj members] {
                puts $member
                incr total_v6
                if { [tmsh::get_field_value $member status.availability-state] == "available" && \
                [tmsh::get_field_value $member status.enabled-state] == "enabled" } {
                    incr usable_v6
                }
              }       
            }
            }
             store the VIPs for a pool in an array v4/v6
            foreach obj [tmsh::get_config /ltm virtual] {
                puts $obj
                set err_pn [tmsh::get_field_value $obj pool pn]
                    set err_dst [tmsh::get_field_value $obj destination vipport]
                    puts $err_pn
                    if { $err_pn == 1 && $err_dst == 1 } {
                        if { $pn == $pni } {
                            puts "bla bla $pn $vipport"
                            set vip($i) [string range $vipport 0 [expr [string last ":" $vipport]-1]]
                                puts $vip($i)
                                incr i
                        } elseif { $pn == $pni_v6 } {
                            set vip_v6($i_v6) [string range $vipport 0 [expr [string last "." $vipport]-1]]
                                puts $vip_v6($i_v6) 
                                incr i_v6
                        }
                    }  
            }
             see if we obey our up/down criteria for a pool and disable VIP BGP advertisement if not
            IPv4
            if { {expr $usable.0 / $total} < $percent } {
                puts "smaller than $percent"
                foreach i [array names vip] {
                    puts $vip($i)
                    foreach member [tmsh::get_config /ltm virtual-address $vip($i)] {
                        puts "member=$member"
                        set err_adv [tmsh::get_field_value $member route-advertisement adv]
                            if { $err_adv == 1 } {
                                puts "inside if"
                                tmsh::modify ltm virtual-address $vip($i) route-advertisement disabled
                                    tmsh::log "Route advertisement disabled for $vip($i)"
                            }
                    }
                }
            } else {
                puts "bigger than $percent"
                foreach i [array names vip] {
                    puts $vip($i)
                    foreach member [tmsh::get_config /ltm virtual-address $vip($i)] {
                        puts "member=$member"
                        set err_adv [tmsh::get_field_value $member route-advertisement adv]
                            if { $err_adv  == 0 } {
                                puts "inside it is disabled"
                                tmsh::modify ltm virtual-address $vip($i) route-advertisement enabled
                                    tmsh::log "Route advertisement enabled for $vip($i)"
                            }
                    }
                }
            }
            IPv6
            if { $pni_v6 != 0 } {
            if { {expr $usable_v6.0 / $total_v6} < $percent } {
                puts "smaller than $percent"
                foreach i_v6 [array names vip_v6] {
                    puts $vip_v6($i_v6)
                    foreach member [tmsh::get_config /ltm virtual-address $vip_v6($i_v6)] {
                        puts "member=$member"
                        set err_adv [tmsh::get_field_value $member route-advertisement adv]
                            if { $err_adv == 1 } {
                                puts "inside if and pool members are not up to the percentage value"
                                tmsh::modify ltm virtual-address $vip_v6($i_v6) route-advertisement disabled
                                    tmsh::log "Route advertisement disabled for $vip_v6($i_v6)"
                            }
                    }
                }
            } else {
                puts "bigger than $percent"
                foreach i_v6 [array names vip_v6] {
                    puts $vip_v6($i_v6)
                    foreach member [tmsh::get_config /ltm virtual-address $vip_v6($i_v6)] {
                        puts "member=$member"
                        set err_adv [tmsh::get_field_value $member route-advertisement adv]
                            if { $err_adv  == 0 } {
                                puts "inside if and pool members should be up"
                                tmsh::modify ltm virtual-address $vip_v6($i_v6) route-advertisement enabled
                                    tmsh::log "Route advertisement enabled for $vip_v6($i_v6)"
                            }
                    }
                }
            }
            }
        }
        description none
        events none
    }
    

    Handler:

    create sys icall handler periodic qlPool_min_members script qlPool_min_members.v1 arguments { { name pni value BLA } { name pni_v6 value V6-BLA } { name percent value 0.5 } } interval 60 first-occurrence 2015-04-04:10:00:00
    

    TODO

    See if there is a nice way to convert the iCall script into an iAPP for easier administration.

    Here I can find no resource on the F5 site...if anyone can help with an example, it would be great:

    • iCall script sample

    • iApp with the same iCall