You do not have permission to view the full content of this post.
Log in or register now.

Tried on openwrt 22
Note: back up first before you replace your controller and view files.
Step 1: replace old controller.
nano /usr/lib/lua/luci/controller/nft-qos.lua
copy & paste
Code:
-- /usr/lib/lua/luci/controller/nft-qos.lua
-- Check if the file exists
if not nixio.fs.access("/tmp/dhcp.leases") then
print("File /tmp/dhcp.leases does not exist.")
return
end
local dhcp_leases = io.open("/tmp/dhcp.leases", "r")
-- Check if the file was opened successfully
if not dhcp_leases then
print("Failed to open file /tmp/dhcp.leases.")
return
end
-- Create a table to map IP addresses to hostnames
local ip_to_hostname = {}
-- Parse the DHCP leases
for line in dhcp_leases:lines() do
-- Each line is a string like: "1625469943 00:0c:29:8d:9e:9a 192.168.1.2 myhostname 01:00:0c:29:8d:9e:9a"
local _, _, ip, hostname = line:match("(%d+) (%S+) (%S+) (%S+)")
-- Add the mapping from IP address to hostname to the table
ip_to_hostname[ip] = hostname
end
-- Close the DHCP leases file
dhcp_leases:close()
module("luci.controller.nft-qos", package.seeall)
function index()
if not nixio.fs.access("/etc/config/nft-qos") then
return
end
local e
e = entry({"admin", "status", "realtime", "rate"}, template("nft-qos/rate"), _("Rate"), 5)
e.leaf = true
e.acl_depends = { "luci-app-nft-qos" }
e = entry({"admin", "status", "realtime", "rate_status"}, call("action_rate"))
e.leaf = true
e.acl_depends = { "luci-app-nft-qos" }
e = entry({"admin", "services", "nft-qos"}, cbi("nft-qos/nft-qos"), _("QoS over Nftables"), 60)
e.leaf = true
e.acl_depends = { "luci-app-nft-qos" }
end
function _action_rate(rv, n)
local c = nixio.fs.access("/proc/net/ipv6_route") and
io.popen("nft list chain inet nft-qos-monitor " .. n .. " 2>/dev/null") or
io.popen("nft list chain ip nft-qos-monitor " .. n .. " 2>/dev/null")
if c then
for l in c:lines() do
local _, i, p, b = l:match('^%s+ip ([^%s]+) ([^%s]+) counter packets (%d+) bytes (%d+)')
if i and p and b then
-- Replace the IP address with the hostname
local hostname = ip_to_hostname[i] or i
-- Use the hostname and IP address in your JSON output
rv[#rv + 1] = {
rule = {
family = "inet",
table = "nft-qos-monitor",
chain = n,
handle = 0,
expr = {
{ match = { right = hostname, ip = i } }, -- Add the IP address here
{ counter = { packets = p, bytes = b } }
}
}
}
end
end
c:close()
end
end
function action_rate()
luci.http.prepare_content("application/json")
local data = { nftables = {} }
_action_rate(data.nftables, "upload")
_action_rate(data.nftables, "download")
luci.http.write_json(data)
end
- Step 2: replace view.htm
copy & paste
Code:
<%#
Copyright 2018 Rosy Song <rosysong@rosinson.com>
Licensed to the public under the Apache License 2.0.
-%>
<%+header%>
<script type="text/javascript">//<![CDATA[
var RC = { };
var em = 0;
var ec = 1;
// console.log(dhcp_leases)
var rate_table_dl;
var rate_table_ul;
function init_bytes(rl, ra) {
var bytes_pre;
var obj = { };
obj.chain = rl.chain;
obj.device = rl.expr[em].match.right;
obj.ipaddr = rl.expr[em].match.ip;
obj.bytes = rl.expr[ec].counter.bytes;
obj.packets = rl.expr[ec].counter.packets;
obj.rate = 0;
//obj.device = deviceMap[obj.ipaddr] || "Unknown device";
if (RC[obj.chain] && RC[obj.chain][obj.ipaddr])
bytes_pre = RC[obj.chain][obj.ipaddr];
else
bytes_pre = 0;
obj.rate = (bytes_pre > 0) ? (obj.bytes - bytes_pre) / 3: 0;
if (!RC[obj.chain])
RC[obj.chain] = { };
RC[obj.chain][obj.ipaddr] = obj.bytes;
if (!ra[obj.chain])
ra[obj.chain] = [ ];
ra[obj.chain].push(obj);
} /* function init_bytes(rl, ra) */
function bytes_label(bytes) {
var uby = '<%:kB%>';
var kby = (bytes / 1024);
if (kby > 1024) {
uby = '<%:MB%>';
kby = (kby / 1024);
}
return String.format("%f %s", kby.toFixed(2), uby);
}
function print_table(tbl, rs, ra) {
ra.sort(function(a, b) { return b.rate - a.rate });
for (var i = 0; i < ra.length; i++) {
rs.push([
ra[i].device,
ra[i].ipaddr,
bytes_label(ra[i].rate) + '/s',
bytes_label(ra[i].bytes),
'%s Pkts.'.format(ra[i].packets),
]);
}
// cbi_update_table(tbl, rs, '<em><%:No information available%></em>');
/* BEGIN: Workaround as "cbi_update_table" isn't working */
rs.forEach((element, i) => {
var r = document.createElement("TR");
r.innerHTML = `
<tr>
<td>${element[0]}</th>
<td>${element[1]}</td>
<td>${element[2]}</td>
<td>${element[3]}</td>
<td>${element[4]}</th>
</tr>
`;
if (i%2){
r.classList.add('tr', 'cbi-rowstyle-2');
} else {
r.classList.add('tr', 'cbi-rowstyle-1');
}
tbl.appendChild(r)
/* END: Workaround as "cbi_update_table" isn't working */
});
} /* function print_table(tbl, ra) */
/* wait for SVG */
window.setTimeout(
function() {
if (!RC)
{
window.setTimeout(arguments.callee, 1000);
}
else
{
rate_table_dl = document.getElementById('rate_table_dl');
rate_table_ul = document.getElementById('rate_table_ul');
/* render datasets, start update interval */
L.Request.poll.add(3, '<%=build_url("admin/status/realtime/rate_status")%>', null,
function(x, json)
{
var RA = {};
var rows_dl = [];
var rows_ul = [];
var rules = json.nftables;
for (var i = 0; i < rules.length; i++)
{
if (!rules[i].rule)
continue;
if (rules[i].rule.table != 'nft-qos-monitor')
continue;
var rl = rules[i].rule;
switch (rl.chain)
{
case 'download':
case 'upload': init_bytes(rl, RA); break;
}
} /* for (var i = 0; i < rules.length; i++) */
/* display the result */
if (RA.download) {
while (rate_table_dl.firstElementChild !== rate_table_dl.lastElementChild)
rate_table_dl.removeChild(rate_table_dl.lastElementChild);
print_table(rate_table_dl, rows_dl, RA.download);
}
if (RA.upload) {
while (rate_table_ul.firstElementChild !== rate_table_ul.lastElementChild)
rate_table_ul.removeChild(rate_table_ul.lastElementChild);
print_table(rate_table_ul, rows_ul, RA.upload);
}
} /* function(x, json) */
);
L.Request.poll.start();
}
}, 1000
);
//]]></script>
<h2 name="content"><%:Realtime Rate%></h2>
<div class="cbi-map-descr"><%:This page gives an overview over currently download/upload rate.%></div>
<fieldset class="cbi-section" id="cbi-table-table">
<legend><%:Realtime Download Rate%></legend>
<div class="cbi-section-node">
<div class="table" id="rate_table_dl">
<div class="tr table-titles">
<div class="th col-2 hide-xs"><%:Device%></div>
<div class="th col-2 hide-xs"><%:Ipaddress%></div>
<div class="th col-2"><%:Download Rate%></div>
<div class="th col-7"><%:Bytes Total%></div>
<div class="th col-7"><%:Packets Total%></div>
</div>
</div>
</div>
</fieldset>
<fieldset class="cbi-section" id="cbi-table-table">
<legend><%:Realtime Upload Rate%></legend>
<div class="cbi-section-node">
<div class="table" id="rate_table_ul">
<div class="tr table-titles">
<div class="th col-2 hide-xs"><%:Device%></div>
<div class="th col-2 hide-xs"><%:Ipaddress%></div>
<div class="th col-2"><%:Upload Rate%></div>
<div class="th col-7"><%:Bytes Total%></div>
<div class="th col-7"><%:Packets Total%></div>
</div>
</div>
</div>
</fieldset>
<%+footer%>
- Step 4: Restart router to apply changes, if you dont want to restart then...
rm -r /tmp/luci-indexcache.xxxxx.xxxx..json
rm -r /tmp/luci-indexcache.xxxxx.lua
/etc/init.d/uhttpd restart