Gather statistics about RF links (#684)

This commit is contained in:
Tim Wilkinson 2023-01-29 19:21:58 -08:00 committed by GitHub
parent fdb9270617
commit 33684d22d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 39 additions and 5 deletions

View File

@ -34,6 +34,7 @@
local ip = require("luci.ip")
local info = require("aredn.info")
local socket = require("socket")
local refresh_timeout = 15 * 60 -- refresh high cost data every 15 minutes
local pending_timeout = 5 * 60 -- pending node wait 5 minutes before they are included
@ -43,6 +44,8 @@ local quality_min_packets = 100 -- minimum number of tx packets before we can sa
local quality_injection_max = 10 -- number of packets to inject into poor links to update quality
local tx_quality_run_avg = 0.8 -- tx quality running average
local ping_timeout = 1.0 -- timeout before ping gives a qualtiy penalty
local ping_time_run_avg = 0.8 -- ping time runnng average
local bitrate_run_avg = 0.8 -- rx/tx running average
local dtd_distance = 50 -- distance (meters) after which nodes connected with DtD links are considered different sites
local connect_timeout = 5 -- timeout (seconds) when fetching information from other nodes
local speed_time = 10 --
@ -280,7 +283,9 @@ function lqm()
["signal avg:"] = "signal",
["tx packets:"] = "tx_packets",
["tx retries:"] = "tx_retries",
["tx failed:"] = "tx_fail"
["tx failed:"] = "tx_fail",
["tx bitrate:"] = "tx_bitrate",
["rx bitrate:"] = "rx_bitrate"
}
local station = {}
local cnoise = iwinfo.nl80211.noise(wlan)
@ -297,7 +302,9 @@ function lqm()
mac = mac:upper(),
signal = 0,
noise = noise,
ip = nil
ip = nil,
tx_bitrate = 0,
rx_bitrate = 0
}
local entry = arps[station.mac]
if entry then
@ -330,7 +337,9 @@ function lqm()
mac = nil,
tx_packets = 0,
tx_fail = 0,
tx_retries = 0
tx_retries = 0,
tx_bitrate = 0,
rx_bitrate = 0
}
stations[#stations + 1] = tunnel
else
@ -361,7 +370,9 @@ function lqm()
mac = mac:upper(),
tx_packets = 0,
tx_fail = 0,
tx_retries = 0
tx_retries = 0,
tx_bitrate = 0,
rx_bitrate = 0
}
end
end
@ -388,7 +399,9 @@ function lqm()
mac = foundmac,
tx_packets = 0,
tx_fail = 0,
tx_retries = 0
tx_retries = 0,
tx_bitrate = 0,
rx_bitrate = 0
}
end
end
@ -429,6 +442,9 @@ function lqm()
last_tx_total = nil,
tx_quality = 100,
ping_quality = 100,
ping_success_time = 0,
tx_bitrate = nil,
rx_bitrate = nil,
quality = 100,
exposed = false
}
@ -471,6 +487,16 @@ function lqm()
track.last_quality = tx_quality
track.tx_quality = math.min(100, math.max(0, math.ceil(tx_quality_run_avg * track.tx_quality + (1 - tx_quality_run_avg) * tx_quality)))
end
if not track.tx_bitrate then
track.tx_bitrate = station.tx_bitrate
else
track.tx_bitrate = track.tx_bitrate * bitrate_run_avg + station.tx_bitrate * (1 - bitrate_run_avg)
end
if not track.rx_bitrate then
track.rx_bitrate = station.rx_bitrate
else
track.rx_bitrate = track.rx_bitrate * bitrate_run_avg + station.rx_bitrate * (1 - bitrate_run_avg)
end
track.lastseen = now
end
@ -609,29 +635,37 @@ function lqm()
track.ping_quality = 100
elseif should_ping(track) then
local success = 100
local ptime = ping_timeout
if track.type == "Tunnel" then
-- Tunnels have no MAC, so we can only use IP level pings.
local sigsock = nixio.socket("inet", "dgram")
sigsock:setopt("socket", "rcvtimeo", ping_timeout)
-- Must connect or we wont see the error
sigsock:connect(track.ip, 8080)
local pstart = socket.gettime(0)
sigsock:send("")
-- There's no actual UDP server at the other end so recv will either timeout and return 'false' if the link is slow,
-- or will error and return 'nil' if there is a node and it send back an ICMP error quickly (which for our purposes is a positive)
if sigsock:recv(0) == false then
success = 0
end
ptime = socket.gettime(0) - pstart
sigsock:close()
else
-- Make an arp request to the target ip to see if we get a timely reply. By using ARP we avoid any
-- potential routing issues and avoid any firewall blocks on the other end.
-- As the request is broadcast, we avoid any potential distance/scope timing issues as we dont wait for the
-- packet to be acked. The reply will be unicast to us, and our ack to that is unimportant to the latency test.
local pstart = socket.gettime(0)
if os.execute(ARPING .. " -f -w " .. ping_timeout .. " -I " .. track.device .. " " .. track.ip .. " >/dev/null") ~= 0 then
success = 0
end
ptime = socket.gettime(0) - pstart
end
local ping_loss_run_avg = 1 - config.ping_penalty / 100
if success > 0 then
track.ping_success_time = track.ping_success_time * ping_time_run_avg + ptime * (1 - ping_time_run_avg)
end
track.ping_quality = math.ceil(ping_loss_run_avg * track.ping_quality + (1 - ping_loss_run_avg) * success)
end