iPerf3 as part of the api (#443)

This commit is contained in:
Tim Wilkinson 2022-07-20 12:42:05 -07:00 committed by GitHub
parent d166393bb8
commit cf8abafd65
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 80 additions and 8 deletions

View File

@ -39,6 +39,7 @@ local nxo = require("nixio")
local ipc = require("luci.ip") local ipc = require("luci.ip")
local auci = require("aredn.uci") local auci = require("aredn.uci")
require("uci") require("uci")
require("luci.sys")
function round2(num, idp) function round2(num, idp)
return tonumber(string.format("%." .. (idp or 0) .. "f", num)) return tonumber(string.format("%." .. (idp or 0) .. "f", num))
@ -305,7 +306,7 @@ function getTraceroute(target)
end end
------------------------------------- -------------------------------------
-- Returns traceroute -- Returns ping
------------------------------------- -------------------------------------
function getPing(target) function getPing(target)
local pings = {} local pings = {}
@ -320,19 +321,19 @@ function getPing(target)
else else
local ip, seq, ttl, time = line:match("bytes from ([%d%.]+): seq=(%d+) ttl=(%d+) time=(%S+) ms") local ip, seq, ttl, time = line:match("bytes from ([%d%.]+): seq=(%d+) ttl=(%d+) time=(%S+) ms")
if ip then if ip then
pings[#pings + 1] = { ip = ip, seq = seq, ttl = ttl, timeMs = time } pings[#pings + 1] = { ip = ip, seq = tonumber(seq), ttl = tonumber(ttl), timeMs = tonumber(time) }
else else
local tx, rx, loss = line:match("^(%d+) packets transmitted, (%d+) packets received, (%d+)%% packet loss") local tx, rx, loss = line:match("^(%d+) packets transmitted, (%d+) packets received, (%d+)%% packet loss")
if tx then if tx then
summary.tx = tx summary.tx = tonumber(tx)
summary.rx = rx summary.rx = tonumber(rx)
summary.lossPercentage = loss summary.lossPercentage = tonumber(loss)
else else
local min, avg, max = line:match("min/avg/max = ([%d%.]+)/([%d%.]+)/([%d%.]+) ms") local min, avg, max = line:match("min/avg/max = ([%d%.]+)/([%d%.]+)/([%d%.]+) ms")
if min then if min then
summary.minMs = min summary.minMs = tonumber(min)
summary.maxMs = max summary.maxMs = tonumber(max)
summary.avgMs = avg summary.avgMs = tonumber(avg)
end end
end end
end end
@ -341,6 +342,65 @@ function getPing(target)
return { summary = summary, pings = pings } return { summary = summary, pings = pings }
end end
-------------------------------------
-- Returns iperf3
-------------------------------------
function getIperf3(target, protocol)
if protocol ~= "udp" then
protocol = "tcp"
end
function toK(value, unit)
return tonumber(value) * (unit == "M" and 1024 or 1)
end
function toM(value, unit)
return tonumber(value) / (unit == "K" and 1024 or 1)
end
local summary = { protocol = protocol, client = {}, server = {}, sender = {}, receiver = {} }
local trace = {}
-- start remote server
luci.sys.httpget("http://" .. target .. ":8080/cgi-bin/iperf?server=")
local output = capture("/usr/bin/iperf3 -b 0 -c " .. target .. (protocol == "udp" and " -u" or "") .. " 2>&1")
for _, line in ipairs(output:splitNewLine())
do
local chost, cport, shost, sport = line:match("local ([%d%.]+) port (%d+) connected to ([%d%.]+) port (%d+)")
if chost then
summary.client = { host = chost, port = tonumber(cport) }
summary.server = { host = shost, port = tonumber(sport) }
else
local from, to, transfer, tu, bitrate, bu, retr = line:match("([%d%.]+)-([%d%.]+)%s+sec%s+([%d%.]+) ([KM])Bytes%s+([%d%.]+) ([MK])bits/sec%s+(%d+)%s+sender")
if from then
summary.sender = { from = tonumber(from), to = tonumber(to), transferMB = toM(transfer, tu), bitrateMb = toM(bitrate, bu), retr = tonumber(retr) }
else
local from, to, transfer, tu, bitrate, bu = line:match("([%d%.]+)-([%d%.]+)%s+sec%s+([%d%.]+) ([KM])Bytes%s+([%d%.]+) ([MK])bits/sec%s+receiver")
if from then
summary.receiver = { from = tonumber(from), to = tonumber(to), transferMB = toM(transfer, tu), bitrateMb = toM(bitrate, bu) }
else
local from, to, transfer, tu, bitrate, bu, jitter, lost, total, percent = line:match("([%d%.]+)-([%d%.]+)%s+sec%s+([%d%.]+) ([KM])Bytes%s+([%d%.]+) ([MK])bits/sec%s+([%d%.]+) ms%s+(%d+)/(%d+) %(([%d%.]+)%%%)%s+sender")
if from then
summary.sender = { from = tonumber(from), to = tonumber(to), transferMB = toM(transfer, tu), bitrateMb = toM(bitrate, bu), jitterMs = tonumber(jitter), lostDgrams = tonumber(lost), totalDgrams = tonumber(total), lossPercentage = tonumber(precent) }
else
local from, to, transfer, tu, bitrate, bu, jitter, lost, total, percent = line:match("([%d%.]+)-([%d%.]+)%s+sec%s+([%d%.]+) ([KM])Bytes%s+([%d%.]+) ([MK])bits/sec%s+([%d%.]+) ms%s+(%d+)/(%d+) %(([%d%.]+)%%%)%s+receiver")
if from then
summary.receiver = { from = tonumber(from), to = tonumber(to), transferMB = toM(transfer, tu), bitrateMb = toM(bitrate, bu), jitterMs = tonumber(jitter), lostDgrams = tonumber(lost), totalDgrams = tonumber(total), lossPercentage = tonumber(precent) }
else
local from, to, transfer, tu, bitrate, bu, retr, cwnd, cu = line:match("([%d%.]+)-([%d%.]+)%s+sec%s+([%d%.]+) ([KM])Bytes%s+([%d%.]+) ([MK])bits/sec%s+(%d+)%s+([%d%.]+) ([KM])Bytes")
if from then
trace[#trace + 1] = { from = tonumber(from), to = tonumber(to), transferMB = toM(transfer, tu), bitrateMb = toM(bitrate, by), retr = tonumber(retr), cwndKB = toK(cwnd, cu) }
else
local from, to, transfer, tu, bitrate, bu, dgrams = line:match("([%d%.]+)-([%d%.]+)%s+sec%s+([%d%.]+) ([KM])Bytes%s+([%d%.]+) ([MK])bits/sec%s+(%d+)")
if from then
trace[#trace + 1] = { from = tonumber(from), to = tonumber(to), transferMB = toM(transfer, tu), bitrateMb = toM(bitrate, bu), dgrams = tonumber(dgrams) }
end
end
end
end
end
end
end
end
return { summary = summary, trace = trace }
end
function file_trim(filename, maxl) function file_trim(filename, maxl)
local lines={} local lines={}
local tmpfilename=filename..".tmp" local tmpfilename=filename..".tmp"

View File

@ -387,6 +387,18 @@ for page, comps in pairs(qsset) do
info['pages'][page][tonode]="Invalid input!" info['pages'][page][tonode]="Invalid input!"
end end
end end
elseif page=="iperf3" then
local protocol = "tcp"
for i,tonode in pairs(comps:split(',')) do
-- Validate that input as ip or hostname inside the mesh
if tonode == "tcp" or tonode == "udp" then
protocol = tonode
elseif tonode:match("^[%d%.]+$") or tonode:match("^[%d%a%-%.%_]+$") then
info['pages'][page][tonode]=getIperf3(tonode, protocol)
else
info['pages'][page][tonode]="Invalid input!"
end
end
elseif page=="mesh" then elseif page=="mesh" then
for i,comp in pairs(comps:split(',')) do for i,comp in pairs(comps:split(',')) do
if comp=="sysinfo" then if comp=="sysinfo" then