class Uplinks
Public Class Methods
new(config)
click to toggle source
# File lib/fault_tolerant_router/uplinks.rb, line 4 def initialize(config) @uplinks = config.each_with_index.map { |uplink, i| Uplink.new(uplink, i) } @uplinks.each { |uplink| uplink.rule_priority_2 = BASE_PRIORITY + @uplinks.size + uplink.id } @default_route_table = @uplinks.map { |uplink| uplink.table }.max + 1 end
Public Instance Methods
all_priority_group_members_down?()
click to toggle source
# File lib/fault_tolerant_router/uplinks.rb, line 138 def all_priority_group_members_down? @uplinks.all? { |uplink| !uplink.priority_group || !uplink.up } end
each() { |uplink| ... }
click to toggle source
# File lib/fault_tolerant_router/uplinks.rb, line 10 def each @uplinks.each { |uplink| yield uplink } end
initialize_routing!()
click to toggle source
# File lib/fault_tolerant_router/uplinks.rb, line 14 def initialize_routing! commands = [] rule_priorities = @uplinks.map { |uplink| [uplink.rule_priority_1, uplink.rule_priority_2] }.flatten.minmax tables = @uplinks.map { |uplink| uplink.table }.minmax #enable IP forwarding commands << 'echo 1 > /proc/sys/net/ipv4/ip_forward' #clean all previous configurations, try to clean more than needed (double) to avoid problems in case of changes in the #number of uplinks between different executions ((rule_priorities.max - rule_priorities.min + 2) * 2).times { |i| commands << "ip rule del priority #{rule_priorities.min + i} &> /dev/null" } ((tables.max - tables.min + 2) * 2).times { |i| commands << "ip route del table #{tables.min + i} &> /dev/null" } #disable "reverse path filtering" on the uplink interfaces commands << 'echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter' commands += @uplinks.map { |uplink| "echo 2 > /proc/sys/net/ipv4/conf/#{uplink.interface}/rp_filter" } #set uplinks routes commands += @uplinks.map { |uplink| uplink.route_add_commands } #rule for first packet of outbound connections commands << "ip rule add priority #{rule_priorities.max + 1} from all lookup #{tables.max + 1}" #set default route commands += update_default_route! #apply the routing changes commands << 'ip route flush cache' commands.flatten end
test!()
click to toggle source
# File lib/fault_tolerant_router/uplinks.rb, line 96 def test! commands = [] messages = [] @uplinks.each do |uplink| c = uplink.test! commands += c end commands += update_default_route! #apply the routing changes, in any commands << 'ip route flush cache' if commands.any? changes = false @uplinks.each do |uplink| current = uplink.ip || 'none' previous = uplink.previous_ip || 'none' changes ||= current != previous ip = current == previous ? current : "#{previous} --> #{current}" current = uplink.gateway || 'none' previous = uplink.previous_gateway || 'none' changes ||= current != previous gateway = current == previous ? current : "#{previous} --> #{current}" current = uplink.up ? 'up' : 'down' previous = uplink.previously_up ? 'up' : 'down' changes ||= current != previous up = current == previous ? current : "#{previous} --> #{current}" current = uplink.default_route ? 'routing' : 'standby' previous = uplink.previously_default_route ? 'routing' : 'standby' changes ||= current != previous default_route = current == previous ? current : "#{previous} --> #{current}" messages << "Uplink #{uplink.description}: ip #{ip}, gateway #{gateway}, #{up}, #{default_route}" end messages = [] unless changes [commands, messages] end
update_default_route!()
click to toggle source
# File lib/fault_tolerant_router/uplinks.rb, line 46 def update_default_route! #select uplinks that are up and with a specified priority group value selected = @uplinks.find_all { |uplink| uplink.up && uplink.priority_group } puts "Choosing default route: available uplinks: #{selected.map { |uplink| uplink.description }.join(', ')}" if DEBUG #restrict the selection to the members of highest priority group highest_available_priority = selected.map { |uplink| uplink.priority_group }.min selected = selected.find_all { |uplink| uplink.priority_group == highest_available_priority } puts "Choosing default route: highest priority group uplinks: #{selected.map { |uplink| uplink.description }.join(', ')}" if DEBUG changes = false #assign default route status to the uplinks and detect changes from previous configuration @uplinks.each do |uplink| uplink.previously_default_route = uplink.default_route uplink.default_route = selected.include?(uplink) changes ||= uplink.default_route != uplink.previously_default_route end #check if any default route uplink changed its gateway (for example due to a ppp update) if @uplinks.any? { |uplink| uplink.default_route && uplink.gateway != uplink.previous_gateway } changes ||= true puts "Choosing default route: detected gateway change in a default route uplink" if DEBUG end commands = [] if selected.size == 0 puts 'Choosing default route: no available uplinks, no need for an update' if DEBUG elsif !changes puts 'Choosing default route: no changes, no need for an update' if DEBUG else puts 'Choosing default route: changes detected, update needed' if DEBUG #do not use balancing if there is just one routing uplink if selected.size == 1 nexthops = "via #{selected.first.gateway}" else nexthops = selected.map do |uplink| #the "weight" parameter is optional tail = uplink.weight ? " weight #{uplink.weight}" : '' "nexthop via #{uplink.gateway}#{tail}" end nexthops = nexthops.join(' ') end #set the route for first packet of outbound connections commands << "ip route replace table #{@default_route_table} default #{nexthops}" end commands end