A scriptable daemon for updating routes based on packet loss to endpoints.
failoverd
is configured using a Lua script that specifies a number of variables and functions.
-- Number of seconds to wait before sending each packet
ping_frequency = 1
-- Number of seconds to wait before calling on_update function
update_frequency = 5
-- Use ICMP pings if true, UDP pings if false
privileged = true
-- The global_probe_stats that are passed to functions are the statistics for the last num_seconds seconds
num_seconds = 10
-- List of endpoints to ping
probes = {
probe.new("192.168.0.1"), -- Pings 192.168.0.1
probe.new("192.168.0.2", "eth0"), -- Pings 192.168.0.2 using eth0's address
}
-- Gets called whenever a response is received
function on_recv(gps, ps)
io.write(string.format("%s: %.2f\n", ps:dst(), ps:loss()))
end
-- Gets called every update_frequency seconds
function on_update(gps)
ps = gps:lowest_loss()
io.write(string.format("%s: %.2f\n", ps:dst(), ps:loss()))
end
-- Gets called on program shutdown (SIGINT)
function on_quit(gps)
print("Shutting down")
end
ping_frequency
: seconds to wait before sending each packet. Default is1
. (number)update_frequency
: seconds to wait before calling on_update function. Default is1
. (number)privileged
: use ICMP pings if true, UDP pings if false. Default isfalse
. (boolean)num_seconds
:failoverd
will keep track of packet loss for this number of seconds. Default is10
. (number)probes
: list of probes to ping (array ofprobe
objects)
Note that if privileged
is true
, then you will need to give failoverd
the CAP_NET_RAW
capability to allow it to send ICMP ping requests, unless you are running it as the superuser.
The following types are implemented for use in the configuration file:
The probe
type is used to specify endpoints that should be pinged. It is created via the probe.new
function, which can be called in two ways:
probe.new(string)
creates a probe where the argument tonew()
is the destination IP address to pingprobe.new(string, string)
creates a probe where the first argument tonew()
is the destination IP address to ping and the second argument is either the source IP address or the network interface whose IP address hould be used as the source
Additionally, probes can be started/stopped during runtime:
probe.start(probe)
starts a new probeprobe.stop(string)
stops the probe with the destination IP address specified by its argument
The global_probe_stats
type stores information about the statistics of all running probes.
It has the following methods:
global_probe_stats::lowest_loss()
returns theprobe_stats
of the probe with the lowest packet lossglobal_probe_stats::get(string)
uses its argument as a destination address and returns the correspondingprobe_stats
The probe_stats
type stores information about the statistics about one running probe.
It has the following methods:
probe_stats::src()
returns the probe's source addressprobe_stats::dst()
returns the probe's destination addressprobe_stats::loss()
returns the probe's current packet loss as a number from 0-100 (percent)
The following functions can be specified in the configuration file; they will be called by failoverd
when indicated. Note that all functions are optional.
on_recv(global_probe_stats, probe_stats)
is called whenever a ping response is received from any endpoint.probe_stats
is the statistics corresponding to the probe for which a response was received.on_update(global_probe_stats)
is called everyupdate_frequency
secondson_quit(global_probe_stats)
is called when the program exits (due to SIGINT)
The following modules are provided:
The dns
module allows for DNS lookups using the system DNS resolver. It provides the following functions:
lookup_v4(string)
looks up the IPv4 addresses for its argument and returns the addresses as an arraylookup_v6(string)
looks up the IPv6 addresses for its argument and returns the addresses as an arraylookup(string)
looks up the IPv4 and IPv6 records for its argument and returns the addresses as an arrayset_timeout(number)
sets the timeout duration for the DNS resolver, in milliseconds
local dns = require("dns")
addresses = dns.lookup_v4("google.com")
for i,addr in ipairs(addresses) do
table.insert(probes, probe.new(addr))
end