mir3c/squashfs-root/usr/sbin/qos_monitor

353 lines
10 KiB
Lua
Executable File

#!/usr/bin/lua
local io = require "io"
local socket = require "socket"
local px = require "Posix"
local devs
local g_interval = 1
local printf=print
local t_now,t_last,t_interval=nil,nil,nil
local batch_mode = false
local DISP={
prefix='\027[',
def={
nothing='0m',
highlight='1m',
bottomline='4m',
flash='5m',
reverse='7m',
show='8m',
fg={
black='30m',
red='31m',
green='32m',
yellow='33m',
blue='34m',
purple='35m',
qin_se='36m',
white='37m',
},
bg={
black='40m',
red='41m',
green='42m',
yellow='43m',
blue='44m',
purple='45m',
qin_se='46m',
white='47m',
},
move_up='%dA', -- %d should be filled with line number
move_down='%dB',
move_right='%dC',
move_left='%dD',
move_x_y='%d;%dH', --- move to pos(x,y)
move_1_1='0;0H', -- move to pos(1,1)
clear='2J', --clear screen
hide_cursor='25l',
show_cursor='25h',
},
}
function run_cmd(cmd)
if not cmd or cmd == "" then
return ""
end
local t=io.popen(cmd)
local a=t:read("*line")
t:close()
return a
end
function read_interfaces(dir)
local tbl={}
local wan=run_cmd("uci -q get network.wan.ifname")
if dir == "u" then
table.insert(tbl,wan)
elseif dir == "d" then
tbl={"ifb0","br-lan"}
else
tbl={"ifb0","br-lan"}
table.insert(tbl,wan)
end
return tbl
end
--split string with chars '$p'
string.split = function(s, p)
local rt= {}
string.gsub(s, '[^'..p..']+', function(w) table.insert(rt, w) end )
return rt
end
function display(p)
if batch_mode then
return '';
end
local v=string.split(p,'.')
if DISP.def[p] then
return DISP.prefix .. DISP.def[p];
elseif DISP.def[v[1]][v[2]] then
return DISP.prefix .. DISP.def['highlight'] .. DISP.prefix .. DISP.def[v[1]][v[2]];
else
return '';
end
end
local sep_line=display('nothing') .. "------------------------------------------------";
local logger=print
local qostype=nil
local function print_r(root,ind)
local indent=" " .. ind
for k,v in pairs(root or {}) do
if(type(v) == "table") then
logger(3,indent .. k .. " = {")
print_r(v,indent)
logger(3, indent .. "}")
elseif(type(v) == "boolean") then
local tmp = 'false'
if v then tmp = 'true' end
logger(3, indent .. k .. '=' .. tmp)
else
logger(3, indent .. k .. "=" .. v)
end
end
end
function update_clock()
t_last=t_now
t_now=socket.gettime()
if t_now and t_last then
t_interval = t_now - t_last
end
end
function get_counters(devs)
local tbl = {}
local status = 'on'
update_clock()
local cmd_tbl = {}
for _,dev in pairs(devs) do
local cmd = "tc -s -d class show dev " .. dev .. "\n"
local pp = io.popen(cmd)
cmd_tbl[dev] = pp:read("*a")
pp:close()
local cmd = "tc -d -s qdisc show dev " .. dev .."|grep root -A 1 " .. "\n"
local pp = io.popen(cmd)
cmd_tbl[dev] = cmd_tbl[dev] .. pp:read("*a")
pp:close()
end
for dev,strs in pairs(cmd_tbl) do
local _lines = string.split(strs,'\n')
local _no=1
local id
while _no <= #_lines do
local tokens=string.split(_lines[_no],' ')
_no = _no + 1
local _idx = 1
while _idx <= #tokens do
if tokens[_idx] == 'class' or tokens[_idx] == 'qdisc' then
_idx = _idx + 1
id=nil
-- class-type
if tokens[_idx] == 'htb' then
if qostype ~= 'htb' then -- clear screen if qos type changed.
printf(display('clear'))
qostype = 'htb'
end
elseif tokens[_idx] == 'prio' then
if qostype ~= 'prio' then
printf(display('clear'))
qostype = 'prio'
end
else
break;
end
_idx = _idx +1
-- class-id
id = tokens[_idx]
tbl[id]={}
tbl[id].dev = dev
_idx = _idx + 1
elseif not id then
break;
elseif tokens[_idx] == 'root' then
_idx = _idx + 1
elseif tokens[_idx] == 'Sent' then
tbl[id]['sent']=tokens[_idx+1]
tbl[id]['sent_pkt']=tokens[_idx+3]
_idx = _idx + 5 -- skip and jump to 'dropped'
elseif tokens[_idx] == 'rate' then
if tbl[id].rate then -- second touch 'rate'
_idx = _idx + 3 -- skip and jump to 'backlog'
else
tbl[id]['rate'] = conv(get_num(tokens[_idx+1]))
_idx = _idx + 2
end
elseif tokens[_idx] == 'ceil' then
tbl[id]['ceil'] = conv(get_num(tokens[_idx+1]))
_idx = _idx + 2
elseif tokens[_idx] == '(dropped' then
tbl[id].dropped = tokens[_idx+1]
_idx = _idx + 2
elseif tokens[_idx] == 'direct_packets_stat' then
tbl[id].direct_packets_stat = tokens[_idx+1]
_idx = _idx + 2
else
tbl[id][tokens[_idx]]=tokens[_idx+1]
_idx = _idx + 2
end
end
end
end
return tbl
end
function print_header()
printf(sep_line)
if verbose then
printf (string.format("%s %6s %7s %3s %6s %9s %9s %8s %8s %11s %9s %4s %7s %6s",
display('fg.yellow'),"dev","classid","pri","quan","rate","ceil(dir)","burst","cburst","sent","speed","drop","backlog","parent"))
else
printf (string.format("%s %6s %7s %9s %9s %9s",display('fg.yellow'),"dev","classid","rate","ceil(dir)","speed"))
end
end
function print_ender()
printf(sep_line)
end
function sleep(n)
socket.select(nil, nil, n)
end
function get_num(nr)
local _,_,num,prefix = string.find(nr,"(%d+)(%S+)")
if prefix == "Kbit" then return num*1024/8
elseif prefix == "Mbit" then return num*1024*1024/8
else return num/8
end
end
function conv(n)
--prefix = "B"
n = n / 1024
prefix = "KB"
if n > 1024 then
n = n/1024
prefix = 'MB'
end
n = string.format("%.2f%s",n,prefix)
return n
end
function main()
verbose = false
batch_mode = false
if arg[1] then
if arg[1] == '-f' then
verbose = true
devs = read_interfaces()
elseif arg[1] == '-u' then
devs = read_interfaces("u")
elseif arg[1] == '-d' then
devs = read_interfaces("d")
elseif arg[1] == '-fu' then
verbose = true
devs = read_interfaces("u")
elseif arg[1] == '-fd' then
verbose = true
devs = read_interfaces("d")
elseif arg[1] == '-b' then -- batch print
verbose = true
batch_mode = true
devs = read_interfaces()
end
else
devs = read_interfaces()
end
lastsent = {}
if verbose then
format = "%s %6s %7s %3s %6s %9s %9s %8s %8s %11s %9s %4s %7s %6s"
else
format = "%s %6s %7s %9s %9s %9s"
end
--io.stdout:setvbuf('line')
--printf (display('clear'))
--printf (display('move_1_1'))
--printf(display('hide_cursor')) -- hide cursor
local clear_count=0
local display_count=3
while display_count > 0 do
if batch_mode then -- just for qos dump
display_count = display_count -1
end
res = get_counters(devs)
if clear_count > 3 then
clear_count = 0
os.execute('clear')
end
clear_count = clear_count +1
printf (display('move_1_1')) -- move cursor to pos(1,1)
print_header()
a={}
for classid in pairs(res) do
table.insert(a,classid)
end
table.sort(a)
output = ''
for _,classid in pairs(a) do
dev = res[classid]['dev'] or ''
direct_packets_stat = res[classid]['direct_packets_stat'] or ''
rate = res[classid]['rate'] or ''
ceil = res[classid]['ceil'] or direct_packets_stat or ''
sent = res[classid]['sent'] or ''
sent_pkt = res[classid]['sent_pkt'] or ''
if verbose then
prio = res[classid]['prio'] or ''
quantum = res[classid]['quantum'] or ''
burst = res[classid]['burst'] or ''
cburst = res[classid]['cburst'] or ''
drop = res[classid]['dropped'] or ''
backlog = res[classid]['backlog'] or ''
parent = res[classid]['parent'] or ''
end
if lastsent[classid] and t_interval then
speed = (sent - lastsent[classid])/t_interval
speed = conv(speed)
else
speed = "0B"
end
lastsent[classid] = sent
if verbose then
if res[classid]['leaf'] then
printf (string.format(format,display('fg.green'),dev,classid,prio,quantum,rate,ceil,burst,cburst,sent_pkt,speed,drop,backlog,parent))
else
printf (string.format(format,display('fg.blue'),dev,classid,prio,quantum,rate,ceil,burst,cburst,sent_pkt,speed,drop,backlog,parent))
end
else
if res[classid]['leaf'] then
printf (string.format(format,display('fg.green'),dev,classid,rate,ceil,speed))
else
printf (string.format(format,display('fg.blue'),dev,classid,rate,ceil,speed))
end
end
end
print_ender()
sleep(g_interval)
end
end
main()