luci-app-qos-gargoyle: import from core

This is only available for this branch.

Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
This commit is contained in:
Tianling Shen 2021-03-23 18:25:01 +08:00
parent 8704d4af19
commit 7ad4177396
No known key found for this signature in database
GPG Key ID: 6850B6345C862176
14 changed files with 1383 additions and 0 deletions

View File

@ -0,0 +1,22 @@
#
# Copyright (C) 2017 Xingwang Liao <kuoruan@gmail.com>
#
# This is free software, licensed under the Apache License, Version 2.0 .
#
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-qos-gargoyle
PKG_VERSION:=1.3.6
PKG_RELEASE:=1
PKG_LICENSE:=Apache-2.0
PKG_MAINTAINER:=Xingwang Liao <kuoruan@gmail.com>
LUCI_TITLE:=LuCI Support for Gargoyle QoS
LUCI_DEPENDS:=+qos-gargoyle
LUCI_PKGARCH:=all
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature

View File

@ -0,0 +1,100 @@
-- Copyright 2017 Xingwang Liao <kuoruan@gmail.com>
-- Licensed to the public under the Apache License 2.0.
module("luci.controller.qos_gargoyle", package.seeall)
local util = require "luci.util"
local http = require "luci.http"
function index()
if not nixio.fs.access("/etc/config/qos_gargoyle") then
return
end
entry({"admin", "network", "qos_gargoyle"},
firstchild(), _("Gargoyle QoS"), 60)
entry({"admin", "network", "qos_gargoyle", "global"},
cbi("qos_gargoyle/global"), _("Global Settings"), 10)
entry({"admin", "network", "qos_gargoyle", "upload"},
cbi("qos_gargoyle/upload"), _("Upload Settings"), 20)
entry({"admin", "network", "qos_gargoyle", "upload", "class"},
cbi("qos_gargoyle/upload_class")).leaf = true
entry({"admin", "network", "qos_gargoyle", "upload", "rule"},
cbi("qos_gargoyle/upload_rule")).leaf = true
entry({"admin", "network", "qos_gargoyle", "download"},
cbi("qos_gargoyle/download"), _("Download Settings"), 30)
entry({"admin", "network", "qos_gargoyle", "download", "class"},
cbi("qos_gargoyle/download_class")).leaf = true
entry({"admin", "network", "qos_gargoyle", "download", "rule"},
cbi("qos_gargoyle/download_rule")).leaf = true
entry({"admin", "network", "qos_gargoyle", "troubleshooting"},
template("qos_gargoyle/troubleshooting"), _("Troubleshooting"), 40)
entry({"admin", "network", "qos_gargoyle", "troubleshooting", "data"},
call("action_troubleshooting_data"))
entry({"admin", "network", "qos_gargoyle", "load_data"},
call("action_load_data")).leaf = true
end
function action_troubleshooting_data()
local uci = require "luci.model.uci".cursor()
local i18n = require "luci.i18n"
local data = {}
local monenabled = uci:get("qos_gargoyle", "download", "qos_monenabled") or "false"
local show_data = util.trim(util.exec("/etc/init.d/qos_gargoyle show 2>/dev/null"))
if show_data == "" then
show_data = i18n.translate("No data found")
end
data.show = show_data
local mon_data
if monenabled == "true" then
mon_data = util.trim(util.exec("cat /tmp/qosmon.status 2>/dev/null"))
if mon_data == "" then
mon_data = i18n.translate("No data found")
end
else
mon_data = i18n.translate("\"Active Congestion Control\" not enabled")
end
data.mon = mon_data
http.prepare_content("application/json")
http.write_json(data)
end
function action_load_data(type)
local device
if type == "download" then
device = "imq0"
elseif type == "upload" then
local qos = require "luci.model.qos_gargoyle"
local wan = qos.get_wan()
device = wan and wan:ifname() or ""
end
if device then
local data
if device ~= "" then
data = util.exec("tc -s class show dev %s 2>/dev/null" % device)
end
http.prepare_content("text/plain")
http.write(data or "")
else
http.status(500, "Bad address")
end
end

View File

@ -0,0 +1,166 @@
-- Copyright 2017 Xingwang Liao <kuoruan@gmail.com>
-- Licensed to the public under the Apache License 2.0.
local wa = require "luci.tools.webadmin"
local uci = require "luci.model.uci".cursor()
local dsp = require "luci.dispatcher"
local http = require "luci.http"
local qos = require "luci.model.qos_gargoyle"
local m, class_s, rule_s, o
local download_classes = {}
local qos_gargoyle = "qos_gargoyle"
uci:foreach(qos_gargoyle, "download_class", function(s)
local class_alias = s.name
if class_alias then
download_classes[#download_classes + 1] = {name = s[".name"], alias = class_alias}
end
end)
m = Map(qos_gargoyle, translate("Download Settings"))
m.template = "qos_gargoyle/list_view"
class_s = m:section(TypedSection, "download_class", translate("Service Classes"),
translate("Each service class is specified by four parameters: percent bandwidth at capacity, "
.. "realtime bandwidth and maximum bandwidth and the minimimze round trip time flag."))
class_s.anonymous = true
class_s.addremove = true
class_s.template = "cbi/tblsection"
class_s.extedit = dsp.build_url("admin/network/qos_gargoyle/download/class/%s")
class_s.create = function(...)
local sid = TypedSection.create(...)
if sid then
m.uci:save(qos_gargoyle)
http.redirect(class_s.extedit % sid)
return
end
end
o = class_s:option(DummyValue, "name", translate("Class Name"))
o.cfgvalue = function(...)
return Value.cfgvalue(...) or translate("None")
end
o = class_s:option(DummyValue, "percent_bandwidth", translate("Percent Bandwidth At Capacity"))
o.cfgvalue = function(...)
local v = tonumber(Value.cfgvalue(...))
if v and v > 0 then
return "%d %%" % v
end
return translate("Not set")
end
o = class_s:option(DummyValue, "min_bandwidth", "%s (kbps)" % translate("Minimum Bandwidth"))
o.cfgvalue = function(...)
local v = tonumber(Value.cfgvalue(...))
return v or translate("Zero")
end
o = class_s:option(DummyValue, "max_bandwidth", "%s (kbps)" % translate("Maximum Bandwidth"))
o.cfgvalue = function(...)
local v = tonumber(Value.cfgvalue(...))
return v or translate("Unlimited")
end
o = class_s:option(DummyValue, "minRTT", translate("Minimize RTT"))
o.cfgvalue = function(...)
local v = Value.cfgvalue(...)
return v and translate(v) or translate("No")
end
o = class_s:option(DummyValue, "_ld", "%s (kbps)" % translate("Load"))
o.rawhtml = true
o.value = "<em class=\"ld-download\">*</em>"
rule_s = m:section(TypedSection, "download_rule", translate("Classification Rules"),
translate("Packets are tested against the rules in the order specified -- rules toward the top "
.. "have priority. As soon as a packet matches a rule it is classified, and the rest of the rules "
.. "are ignored. The order of the rules can be altered using the arrow controls.")
)
rule_s.addremove = true
rule_s.sortable = true
rule_s.anonymous = true
rule_s.template = "cbi/tblsection"
rule_s.extedit = dsp.build_url("admin/network/qos_gargoyle/download/rule/%s")
rule_s.create = function(...)
local sid = TypedSection.create(...)
if sid then
m.uci:save(qos_gargoyle)
http.redirect(rule_s.extedit % sid)
return
end
end
o = rule_s:option(ListValue, "class", translate("Service Class"))
for _, s in ipairs(download_classes) do o:value(s.name, s.alias) end
o = rule_s:option(Value, "proto", translate("Transport Protocol"))
o:value("", translate("All"))
o:value("tcp", "TCP")
o:value("udp", "UDP")
o:value("icmp", "ICMP")
o:value("gre", "GRE")
o.size = "10"
o.cfgvalue = function(...)
local v = Value.cfgvalue(...)
return v and v:upper() or ""
end
o.write = function(self, section, value)
Value.write(self, section, value:lower())
end
o = rule_s:option(Value, "source", translate("Source IP(s)"))
o:value("", translate("All"))
wa.cbi_add_knownips(o)
o.datatype = "ipmask4"
o = rule_s:option(Value, "srcport", translate("Source Port(s)"))
o:value("", translate("All"))
o.datatype = "or(port, portrange)"
o = rule_s:option(Value, "destination", translate("Destination IP(s)"))
o:value("", translate("All"))
wa.cbi_add_knownips(o)
o.datatype = "ipmask4"
o = rule_s:option(Value, "dstport", translate("Destination Port(s)"))
o:value("", translate("All"))
o.datatype = "or(port, portrange)"
o = rule_s:option(DummyValue, "min_pkt_size", translate("Minimum Packet Length"))
o.cfgvalue = function(...)
local v = tonumber(Value.cfgvalue(...))
if v and v > 0 then
return wa.byte_format(v)
end
return translate("Not set")
end
o = rule_s:option(DummyValue, "max_pkt_size", translate("Maximum Packet Length"))
o.cfgvalue = function(...)
local v = tonumber(Value.cfgvalue(...))
if v and v > 0 then
return wa.byte_format(v)
end
return translate("Not set")
end
o = rule_s:option(DummyValue, "connbytes_kb", translate("Connection Bytes Reach"))
o.cfgvalue = function(...)
local v = tonumber(Value.cfgvalue(...))
if v and v > 0 then
return wa.byte_format(v * 1024)
end
return translate("Not set")
end
if qos.has_ndpi() then
o = rule_s:option(DummyValue, "ndpi", translate("DPI Protocol"))
o.cfgvalue = function(...)
local v = Value.cfgvalue(...)
return v and v:upper() or translate("All")
end
end
return m

View File

@ -0,0 +1,61 @@
-- Copyright 2017 Xingwang Liao <kuoruan@gmail.com>
-- Licensed to the public under the Apache License 2.0.
local m, s, o
local sid = arg[1]
local qos_gargoyle = "qos_gargoyle"
m = Map(qos_gargoyle, translate("Edit Download Service Class"))
m.redirect = luci.dispatcher.build_url("admin/network/qos_gargoyle/download")
if m.uci:get(qos_gargoyle, sid) ~= "download_class" then
luci.http.redirect(m.redirect)
return
end
s = m:section(NamedSection, sid, "download_class")
s.anonymous = true
s.addremove = false
o = s:option(Value, "name", translate("Service Class Name"))
o.rmempty = false
o = s:option(Value, "percent_bandwidth", translate("Percent Bandwidth At Capacity"),
translate("The percentage of the total available bandwidth that should be allocated to this class "
.. "when all available bandwidth is being used. If unused bandwidth is available, more can (and "
.. "will) be allocated. The percentages can be configured to equal more (or less) than 100, but "
.. "when the settings are applied the percentages will be adjusted proportionally so that they "
.. "add to 100. This setting only comes into effect when the WAN link is saturated."))
o.datatype = "range(1, 100)"
o.rmempty = false
o = s:option(Value, "min_bandwidth", translate("Minimum Bandwidth"),
translate("The minimum service this class will be allocated when the link is at capacity. Classes "
.. "which specify minimum service are known as realtime classes by the active congestion "
.. "controller. Streaming video, VoIP and interactive online gaming are all examples of "
.. "applications that must have a minimum bandwith to function. To determine what to enter use "
.. "the application on an unloaded LAN and observe how much bandwidth it uses. Then enter a "
.. "number only slightly higher than this into this field. QoS will satisfiy the minimum service "
.. "of all classes first before allocating to other waiting classes so be careful to use minimum "
.. "bandwidths sparingly."))
o:value("0", translate("Zero"))
o.datatype = "uinteger"
o.default = "0"
o = s:option(Value, "max_bandwidth", translate("Maximum Bandwidth"),
translate("The maximum amount of bandwidth this class will be allocated in kbit/s. Even if unused "
.. "bandwidth is available, this service class will never be permitted to use more than this "
.. "amount of bandwidth."))
o:value("", translate("Unlimited"))
o.datatype = "uinteger"
o = s:option(Flag, "minRTT", translate("Minimize RTT"),
translate("Indicates to the active congestion controller that you wish to minimize round trip "
.. "times (RTT) when this class is active. Use this setting for online gaming or VoIP "
.. "applications that need low round trip times (ping times). Minimizing RTT comes at the expense "
.. "of efficient WAN throughput so while these class are active your WAN throughput will decline "
.. "(usually around 20%)."))
o.enabled = "Yes"
o.disabled = "No"
return m

View File

@ -0,0 +1,87 @@
-- Copyright 2017 Xingwang Liao <kuoruan@gmail.com>
-- Licensed to the public under the Apache License 2.0.
local wa = require "luci.tools.webadmin"
local uci = require "luci.model.uci".cursor()
local qos = require "luci.model.qos_gargoyle"
local m, s, o
local sid = arg[1]
local download_classes = {}
local qos_gargoyle = "qos_gargoyle"
uci:foreach(qos_gargoyle, "download_class", function(s)
local class_alias = s.name
if class_alias then
download_classes[#download_classes + 1] = {name = s[".name"], alias = class_alias}
end
end)
m = Map(qos_gargoyle, translate("Edit Download Classification Rule"))
m.redirect = luci.dispatcher.build_url("admin/network/qos_gargoyle/download")
if m.uci:get(qos_gargoyle, sid) ~= "download_rule" then
luci.http.redirect(m.redirect)
return
end
s = m:section(NamedSection, sid, "download_rule")
s.anonymous = true
s.addremove = false
o = s:option(ListValue, "class", translate("Service Class"))
for _, s in ipairs(download_classes) do o:value(s.name, s.alias) end
o = s:option(Value, "proto", translate("Transport Protocol"))
o:value("", translate("All"))
o:value("tcp", "TCP")
o:value("udp", "UDP")
o:value("icmp", "ICMP")
o:value("gre", "GRE")
o.write = function(self, section, value)
Value.write(self, section, value:lower())
end
o = s:option(Value, "source", translate("Source IP(s)"),
translate("Packet's source ip, can optionally have /[mask] after it (see -s option in iptables "
.. "man page)."))
o:value("", translate("All"))
wa.cbi_add_knownips(o)
o.datatype = "ipmask4"
o = s:option(Value, "srcport", translate("Source Port(s)"),
translate("Packet's source port, can be a range (eg. 80-90)."))
o:value("", translate("All"))
o.datatype = "or(port, portrange)"
o = s:option(Value, "destination", translate("Destination IP(s)"),
translate("Packet's destination ip, can optionally have /[mask] after it (see -d option in "
.. "iptables man page)."))
o:value("", translate("All"))
wa.cbi_add_knownips(o)
o.datatype = "ipmask4"
o = s:option(Value, "dstport", translate("Destination Port(s)"),
translate("Packet's destination port, can be a range (eg. 80-90)."))
o:value("", translate("All"))
o.datatype = "or(port, portrange)"
o = s:option(Value, "min_pkt_size", translate("Minimum Packet Length"),
translate("Packet's minimum size (in bytes)."))
o.datatype = "range(1, 1500)"
o = s:option(Value, "max_pkt_size", translate("Maximum Packet Length"),
translate("Packet's maximum size (in bytes)."))
o.datatype = "range(1, 1500)"
o = s:option(Value, "connbytes_kb", translate("Connection Bytes Reach"),
translate("The total size of data transmitted since the establishment of the link (in kBytes)."))
o.datatype = "range(0, 4194303)"
if qos.has_ndpi() then
o = s:option(ListValue, "ndpi", translate("DPI Protocol"))
o:value("", translate("All"))
qos.cbi_add_dpi_protocols(o)
end
return m

View File

@ -0,0 +1,123 @@
-- Copyright 2017 Xingwang Liao <kuoruan@gmail.com>
-- Licensed to the public under the Apache License 2.0.
local sys = require "luci.sys"
local uci = require "luci.model.uci".cursor()
local net = require "luci.model.network".init()
local qos = require "luci.model.qos_gargoyle"
local m, s, o
local upload_classes = {}
local download_classes = {}
local qos_gargoyle = "qos_gargoyle"
local function qos_enabled()
return sys.init.enabled(qos_gargoyle)
end
uci:foreach(qos_gargoyle, "upload_class", function(s)
local class_alias = s.name
if class_alias then
upload_classes[#upload_classes + 1] = {name = s[".name"], alias = class_alias}
end
end)
uci:foreach(qos_gargoyle, "download_class", function(s)
local class_alias = s.name
if class_alias then
download_classes[#download_classes + 1] = {name = s[".name"], alias = class_alias}
end
end)
m = Map(qos_gargoyle, translate("Gargoyle QoS"),
translate("Quality of Service (QoS) provides a way to control how available bandwidth is "
.. "allocated."))
s = m:section(SimpleSection, translate("Global Settings"))
s.anonymous = true
o = s:option(Button, "_switch", nil, translate("QoS Switch"))
o.render = function(self, section, scope)
if qos_enabled() then
self.title = translate("Disable QoS")
self.inputstyle = "reset"
else
self.title = translate("Enable QoS")
self.inputstyle = "apply"
end
Button.render(self, section, scope)
end
o.write = function(...)
if qos_enabled() then
sys.init.stop(qos_gargoyle)
sys.init.disable(qos_gargoyle)
else
sys.init.enable(qos_gargoyle)
sys.init.start(qos_gargoyle)
end
end
s = m:section(NamedSection, "upload", "upload", translate("Upload Settings"))
s.anonymous = true
o = s:option(ListValue, "default_class", translate("Default Service Class"),
translate("Specifie how packets that do not match any rule should be classified."))
for _, s in ipairs(upload_classes) do o:value(s.name, s.alias) end
o = s:option(Value, "total_bandwidth", translate("Total Upload Bandwidth"),
translate("Should be set to around 98% of your available upload bandwidth. Entering a number "
.. "which is too high will result in QoS not meeting its class requirements. Entering a number "
.. "which is too low will needlessly penalize your upload speed. You should use a speed test "
.. "program (with QoS off) to determine available upload bandwidth. Note that bandwidth is "
.. "specified in kbps, leave blank to disable update QoS. There are 8 kilobits per kilobyte."))
o.datatype = "uinteger"
s = m:section(NamedSection, "download", "download", translate("Download Settings"))
s.anonymous = true
o = s:option(ListValue, "default_class", translate("Default Service Class"),
translate("Specifie how packets that do not match any rule should be classified."))
for _, s in ipairs(download_classes) do o:value(s.name, s.alias) end
o = s:option(Value, "total_bandwidth", translate("Total Download Bandwidth"),
translate("Specifying correctly is crucial to making QoS work. Note that bandwidth is specified "
.. "in kbps, leave blank to disable download QoS. There are 8 kilobits per kilobyte."))
o.datatype = "uinteger"
o = s:option(Flag, "qos_monenabled", translate("Enable Active Congestion Control"),
translate("<p>The active congestion control (ACC) observes your download activity and "
.. "automatically adjusts your download link limit to maintain proper QoS performance. ACC "
.. "automatically compensates for changes in your ISP's download speed and the demand from your "
.. "network adjusting the link speed to the highest speed possible which will maintain proper QoS "
.. "function. The effective range of this control is between 15% and 100% of the total download "
.. "bandwidth you entered above.</p>") ..
translate("<p>While ACC does not adjust your upload link speed you must enable and properly "
.. "configure your upload QoS for it to function properly.</p>")
)
o.enabled = "true"
o.disabled = "false"
o = s:option(Value, "ptarget_ip", translate("Use Non-standard Ping Target"),
translate("The segment of network between your router and the ping target is where congestion is "
.. "controlled. By monitoring the round trip ping times to the target congestion is detected. By "
.. "default ACC uses your WAN gateway as the ping target. If you know that congestion on your "
.. "link will occur in a different segment then you can enter an alternate ping target. Leave "
.. "empty to use the default settings."))
o:depends("qos_monenabled", "true")
local wan = qos.get_wan()
if wan then o:value(wan:gwaddr()) end
o.datatype = "ipaddr"
o = s:option(Value, "pinglimit", translate("Manual Ping Limit"),
translate("Round trip ping times are compared against the ping limits. ACC controls the link "
.. "limit to maintain ping times under the appropriate limit. By default ACC attempts to "
.. "automatically select appropriate target ping limits for you based on the link speeds you "
.. "entered and the performance of your link it measures during initialization. You cannot change "
.. "the target ping time for the minRTT mode but by entering a manual time you can control the "
.. "target ping time of the active mode. The time you enter becomes the increase in the target "
.. "ping time between minRTT and active mode. Leave empty to use the default settings."))
o:depends("qos_monenabled", "true")
o:value("Auto", translate("Auto"))
o.datatype = "or('Auto', range(10, 250))"
return m

View File

@ -0,0 +1,160 @@
-- Copyright 2017 Xingwang Liao <kuoruan@gmail.com>
-- Licensed to the public under the Apache License 2.0.
local wa = require "luci.tools.webadmin"
local uci = require "luci.model.uci".cursor()
local dsp = require "luci.dispatcher"
local http = require "luci.http"
local qos = require "luci.model.qos_gargoyle"
local m, class_s, rule_s, o
local upload_classes = {}
local qos_gargoyle = "qos_gargoyle"
uci:foreach(qos_gargoyle, "upload_class", function(s)
local class_alias = s.name
if class_alias then
upload_classes[#upload_classes + 1] = {name = s[".name"], alias = class_alias}
end
end)
m = Map(qos_gargoyle, translate("Upload Settings"))
m.template = "qos_gargoyle/list_view"
class_s = m:section(TypedSection, "upload_class", translate("Service Classes"),
translate("Each upload service class is specified by three parameters: percent bandwidth at "
.. "capacity, minimum bandwidth and maximum bandwidth."))
class_s.anonymous = true
class_s.addremove = true
class_s.template = "cbi/tblsection"
class_s.extedit = dsp.build_url("admin/network/qos_gargoyle/upload/class/%s")
class_s.create = function(...)
local sid = TypedSection.create(...)
if sid then
m.uci:save(qos_gargoyle)
http.redirect(class_s.extedit % sid)
return
end
end
o = class_s:option(DummyValue, "name", translate("Class Name"))
o.cfgvalue = function(...)
return Value.cfgvalue(...) or translate("None")
end
o = class_s:option(DummyValue, "percent_bandwidth", translate("Percent Bandwidth At Capacity"))
o.cfgvalue = function(...)
local v = tonumber(Value.cfgvalue(...))
if v and v > 0 then
return "%d %%" % v
end
return translate("Not set")
end
o = class_s:option(DummyValue, "min_bandwidth", "%s (kbps)" % translate("Minimum Bandwidth"))
o.cfgvalue = function(...)
local v = tonumber(Value.cfgvalue(...))
return v or translate("Zero")
end
o = class_s:option(DummyValue, "max_bandwidth", "%s (kbps)" % translate("Maximum Bandwidth"))
o.cfgvalue = function(...)
local v = tonumber(Value.cfgvalue(...))
return v or translate("Unlimited")
end
o = class_s:option(DummyValue, "_ld", "%s (kbps)" % translate("Load"))
o.rawhtml = true
o.value = "<em class=\"ld-upload\">*</em>"
rule_s = m:section(TypedSection, "upload_rule",translate("Classification Rules"),
translate("Packets are tested against the rules in the order specified -- rules toward the top "
.. "have priority. As soon as a packet matches a rule it is classified, and the rest of the rules "
.. "are ignored. The order of the rules can be altered using the arrow controls.")
)
rule_s.addremove = true
rule_s.sortable = true
rule_s.anonymous = true
rule_s.template = "cbi/tblsection"
rule_s.extedit = dsp.build_url("admin/network/qos_gargoyle/upload/rule/%s")
rule_s.create = function(...)
local sid = TypedSection.create(...)
if sid then
m.uci:save(qos_gargoyle)
http.redirect(rule_s.extedit % sid)
return
end
end
o = rule_s:option(ListValue, "class", translate("Service Class"))
for _, s in ipairs(upload_classes) do o:value(s.name, s.alias) end
o = rule_s:option(Value, "proto", translate("Transport Protocol"))
o:value("", translate("All"))
o:value("tcp", "TCP")
o:value("udp", "UDP")
o:value("icmp", "ICMP")
o:value("gre", "GRE")
o.size = "10"
o.cfgvalue = function(...)
local v = Value.cfgvalue(...)
return v and v:upper() or ""
end
o.write = function(self, section, value)
Value.write(self, section, value:lower())
end
o = rule_s:option(Value, "source", translate("Source IP(s)"))
o:value("", translate("All"))
wa.cbi_add_knownips(o)
o.datatype = "ipmask4"
o = rule_s:option(Value, "srcport", translate("Source Port(s)"))
o:value("", translate("All"))
o.datatype = "or(port, portrange)"
o = rule_s:option(Value, "destination", translate("Destination IP(s)"))
o:value("", translate("All"))
wa.cbi_add_knownips(o)
o.datatype = "ipmask4"
o = rule_s:option(Value, "dstport", translate("Destination Port(s)"))
o:value("", translate("All"))
o.datatype = "or(port, portrange)"
o = rule_s:option(DummyValue, "min_pkt_size", translate("Minimum Packet Length"))
o.cfgvalue = function(...)
local v = tonumber(Value.cfgvalue(...))
if v and v > 0 then
return wa.byte_format(v)
end
return translate("Not set")
end
o = rule_s:option(DummyValue, "max_pkt_size", translate("Maximum Packet Length"))
o.cfgvalue = function(...)
local v = tonumber(Value.cfgvalue(...))
if v and v > 0 then
return wa.byte_format(v)
end
return translate("Not set")
end
o = rule_s:option(DummyValue, "connbytes_kb", translate("Connection Bytes Reach"))
o.cfgvalue = function(...)
local v = tonumber(Value.cfgvalue(...))
if v and v > 0 then
return wa.byte_format(v * 1024)
end
return translate("Not set")
end
if qos.has_ndpi() then
o = rule_s:option(DummyValue, "ndpi", translate("DPI Protocol"))
o.cfgvalue = function(...)
local v = Value.cfgvalue(...)
return v and v:upper() or translate("All")
end
end
return m

View File

@ -0,0 +1,52 @@
-- Copyright 2017 Xingwang Liao <kuoruan@gmail.com>
-- Licensed to the public under the Apache License 2.0.
local m, s, o
local sid = arg[1]
local qos_gargoyle = "qos_gargoyle"
m = Map(qos_gargoyle, translate("Edit Upload Service Class"))
m.redirect = luci.dispatcher.build_url("admin/network/qos_gargoyle/upload")
if m.uci:get(qos_gargoyle, sid) ~= "upload_class" then
luci.http.redirect(m.redirect)
return
end
s = m:section(NamedSection, sid, "upload_class")
s.anonymous = true
s.addremove = false
o = s:option(Value, "name", translate("Service Class Name"))
o.rmempty = false
o = s:option(Value, "percent_bandwidth", translate("Percent Bandwidth At Capacity"),
translate("The percentage of the total available bandwidth that should be allocated to this class "
.. "when all available bandwidth is being used. If unused bandwidth is available, more can (and "
.. "will) be allocated. The percentages can be configured to equal more (or less) than 100, but "
.. "when the settings are applied the percentages will be adjusted proportionally so that they "
.. "add to 100. This setting only comes into effect when the WAN link is saturated."))
o.datatype = "range(1, 100)"
o.rmempty = false
o = s:option(Value, "min_bandwidth", translate("Minimum Bandwidth"),
translate("The minimum service this class will be allocated when the link is at capacity. Classes "
.. "which specify minimum service are known as realtime classes by the active congestion "
.. "controller. Streaming video, VoIP and interactive online gaming are all examples of "
.. "applications that must have a minimum bandwith to function. To determine what to enter use "
.. "the application on an unloaded LAN and observe how much bandwidth it uses. Then enter a "
.. "number only slightly higher than this into this field. QoS will satisfiy the minimum service "
.. "of all classes first before allocating to other waiting classes so be careful to use minimum "
.. "bandwidths sparingly."))
o:value("0", translate("Zero"))
o.datatype = "uinteger"
o.default = "0"
o = s:option(Value, "max_bandwidth", translate("Maximum Bandwidth"),
translate("The maximum amount of bandwidth this class will be allocated in kbit/s. Even if unused "
.. "bandwidth is available, this service class will never be permitted to use more than this "
.. "amount of bandwidth."))
o:value("", translate("Unlimited"))
o.datatype = "uinteger"
return m

View File

@ -0,0 +1,87 @@
-- Copyright 2017 Xingwang Liao <kuoruan@gmail.com>
-- Licensed to the public under the Apache License 2.0.
local wa = require "luci.tools.webadmin"
local uci = require "luci.model.uci".cursor()
local qos = require "luci.model.qos_gargoyle"
local m, s, o
local sid = arg[1]
local upload_classes = {}
local qos_gargoyle = "qos_gargoyle"
uci:foreach(qos_gargoyle, "upload_class", function(s)
local class_alias = s.name
if class_alias then
upload_classes[#upload_classes + 1] = {name = s[".name"], alias = class_alias}
end
end)
m = Map(qos_gargoyle, translate("Edit Upload Classification Rule"))
m.redirect = luci.dispatcher.build_url("admin/network/qos_gargoyle/upload")
if m.uci:get(qos_gargoyle, sid) ~= "upload_rule" then
luci.http.redirect(m.redirect)
return
end
s = m:section(NamedSection, sid, "upload_rule")
s.anonymous = true
s.addremove = false
o = s:option(ListValue, "class", translate("Service Class"))
for _, s in ipairs(upload_classes) do o:value(s.name, s.alias) end
o = s:option(Value, "proto", translate("Transport Protocol"))
o:value("", translate("All"))
o:value("tcp", "TCP")
o:value("udp", "UDP")
o:value("icmp", "ICMP")
o:value("gre", "GRE")
o.write = function(self, section, value)
Value.write(self, section, value:lower())
end
o = s:option(Value, "source", translate("Source IP(s)"),
translate("Packet's source ip, can optionally have /[mask] after it (see -s option in iptables "
.. "man page)."))
o:value("", translate("All"))
wa.cbi_add_knownips(o)
o.datatype = "ipmask4"
o = s:option(Value, "srcport", translate("Source Port(s)"),
translate("Packet's source port, can be a range (eg. 80-90)."))
o:value("", translate("All"))
o.datatype = "or(port, portrange)"
o = s:option(Value, "destination", translate("Destination IP(s)"),
translate("Packet's destination ip, can optionally have /[mask] after it (see -d option in "
.. "iptables man page)."))
o:value("", translate("All"))
wa.cbi_add_knownips(o)
o.datatype = "ipmask4"
o = s:option(Value, "dstport", translate("Destination Port(s)"),
translate("Packet's destination port, can be a range (eg. 80-90)."))
o:value("", translate("All"))
o.datatype = "or(port, portrange)"
o = s:option(Value, "min_pkt_size", translate("Minimum Packet Length"),
translate("Packet's minimum size (in bytes)."))
o.datatype = "range(1, 1500)"
o = s:option(Value, "max_pkt_size", translate("Maximum Packet Length"),
translate("Packet's maximum size (in bytes)."))
o.datatype = "range(1, 1500)"
o = s:option(Value, "connbytes_kb", translate("Connection Bytes Reach"),
translate("The total size of data transmitted since the establishment of the link (in kBytes)."))
o.datatype = "range(0, 4194303)"
if qos.has_ndpi() then
o = s:option(ListValue, "ndpi", translate("DPI Protocol"))
o:value("", translate("All"))
qos.cbi_add_dpi_protocols(o)
end
return m

View File

@ -0,0 +1,31 @@
-- Copyright 2017 Xingwang Liao <kuoruan@gmail.com>
-- Licensed to the public under the Apache License 2.0.
module("luci.model.qos_gargoyle", package.seeall)
function has_ndpi()
return luci.sys.call("lsmod | cut -d ' ' -f1 | grep -q 'xt_ndpi'") == 0
end
function cbi_add_dpi_protocols(field)
local util = require "luci.util"
local dpi_protocols = {}
for line in util.execi("iptables -m ndpi --help 2>/dev/null | grep '^--'") do
local _, _, protocol, name = line:find("%-%-([^%s]+) Match for ([^%s]+)")
if protocol and name then
dpi_protocols[protocol] = name
end
end
for p, n in util.kspairs(dpi_protocols) do
field:value(p, n)
end
end
function get_wan()
local net = require "luci.model.network".init()
return net:get_wannet()
end

View File

@ -0,0 +1,97 @@
<%#
Copyright 2017 Xingwang Liao <kuoruan@gmail.com>
Licensed to the public under the Apache License 2.0.
-%>
<%
local dsp = require "luci.dispatcher"
local request = dsp.context.path
local leaf = request[#request]
-%>
<style title="text/css">
/* container for entire page. fixes bootstrap theme's ridiculously small page width */
.container {
max-width: none;
margin: 0 30px;
width: auto;
}
/* column for configuration section name */
table th {
padding: 5px 0;
text-align: center;
vertical-align: middle;
}
/* cells showing the configuration values */
table td {
padding: 5px 0;
text-align: center;
vertical-align: middle;
}
/* sort buttons column */
table.cbi-section-table td.cbi-section-table-cell {
text-align: center;
}
</style>
<%+cbi/map%>
<script type="text/javascript">//<![CDATA[
function bpsToKbpsString(bps) {
var kbps = '*';
var bpsn = parseInt(bps) / 1000;
if (isNaN(bpsn)) {
kbps = '*';
} else if (bpsn < 1) {
kbps = bpsn.toFixed(1) + '';
} else {
kbps = bpsn.toFixed(0) + '';
}
return kbps;
}
(function(doc){
var tbs = doc.getElementsByClassName('ld-<%=leaf%>');
var lastTime = 0;
var dataTable = [];
var updateInProgress = false;
XHR.poll(3, '<%=dsp.build_url("admin", "network", "qos_gargoyle", "load_data", leaf)%>',
null, function(res) {
if (res.readyState == 4 && tbs) {
var timestamp = new Date().getTime();
var timeDiff = timestamp - lastTime;
lastTime = timestamp;
if (updateInProgress) return;
updateInProgress = true;
var lines = res.responseText.match(/hfsc\s1:[0-9]{1,2}\s.+leaf.+\n.+Sent\s[0-9]+/g);
if (lines) {
for (var i = 0, len = lines.length; i < len; i++) {
var line = lines[i];
var idx = parseInt(line.match(/hfsc\s1:([0-9]+)/)[1]) - 2;
var lastBytes;
if (idx < tbs.length) {
lastBytes = dataTable[idx];
var newBytes = line.match(/Sent\s([0-9]+)/)[1];
dataTable[idx] = newBytes;
var bps = NaN;
if (lastBytes) {
var diffBytes = parseInt(newBytes) - parseInt(lastBytes);
if (diffBytes <= 0) {
bps = 0;
} else {
bps = diffBytes * 8000 / timeDiff;
}
}
tbs[idx].innerText = bpsToKbpsString(bps);
}
}
}
updateInProgress = false;
}
}
);
}(document));
//]]></script>

View File

@ -0,0 +1,52 @@
<%#
Copyright 2017 Xingwang Liao <kuoruan@gmail.com>
Licensed to the public under the Apache License 2.0.
-%>
<% css = [[
#troubleshoot_text {
padding: 20px;
text-align: left;
}
#troubleshoot_text pre {
word-break: break-all;
margin: 0;
}
.description {
background-color: #33CCFF;
}
]]
-%>
<%+header%>
<script type="text/javascript" src="<%=resource%>/cbi.js"></script>
<script type="text/javascript">//<![CDATA[
XHR.poll(15, '<%=url("admin/network/qos_gargoyle/troubleshooting/data")%>', null,
function(x, data) {
var tshoot = document.getElementById('troubleshoot_text');
if (data.hasOwnProperty("show")) {
tshoot.innerHTML = String.format(
'<pre>%s%s%s%s</pre>',
'<span class="description">Output of &#34;/etc/init.d/qos_gargoyle show&#34; : </span><br /><br />',
data.show,
'<br /><br /><span class="description">Output of &#34;cat /tmp/qosmon.status&#34; : </span><br /><br />',
data.mon
);
} else {
tshoot.innerHTML = '<strong><%:Error collecting troubleshooting information%></strong>';
}
}
);
//]]></script>
<div id="troubleshoot">
<fieldset class="cbi-section">
<legend><%:Troubleshooting Data%></legend>
<div id="troubleshoot_text"><img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align:middle" /><%:Collecting data...%></div>
</fieldset>
</div>
<%+footer%>

View File

@ -0,0 +1,334 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8\n"
msgid "\"Active Congestion Control\" not enabled"
msgstr "“主动拥塞控制”未启用"
msgid ""
"<p>The active congestion control (ACC) observes your download activity and "
"automatically adjusts your download link limit to maintain proper QoS "
"performance. ACC automatically compensates for changes in your ISP's "
"download speed and the demand from your network adjusting the link speed to "
"the highest speed possible which will maintain proper QoS function. The "
"effective range of this control is between 15% and 100% of the total "
"download bandwidth you entered above.</p>"
msgstr ""
"<p>主动拥塞控制系统ACC观察你的下载活动并自动调整你的下载链接限制以保持适"
"当的 QoS 性能。ACC 自动调整 QoS 功能以补偿来自你 ISP 的下载速度变化及来自你网"
"络链接速度的调整需求,使速度最大化。这个控制的有效范围在你上面输入的下载总带"
"宽的 15% 至 100% 之间。</p>"
msgid ""
"<p>While ACC does not adjust your upload link speed you must enable and "
"properly configure your upload QoS for it to function properly.</p>"
msgstr ""
"<p>虽然 ACC 不调整你的上传链路速度,但你必须启用并正确配置你的上传 QoS 带宽以"
"使该功能正常工作。</p>"
msgid "All"
msgstr "全部"
msgid "Auto"
msgstr "自动"
msgid "Class Name"
msgstr "类型名称"
msgid "Classification Rules"
msgstr "分类规则"
msgid "Collecting data..."
msgstr "正在收集数据..."
msgid "Connection Bytes Reach"
msgstr "连接流量达到"
msgid "DPI Protocol"
msgstr "DPI 协议"
msgid "Default Service Class"
msgstr "默认服务类型"
msgid "Destination IP(s)"
msgstr "目标 IP"
msgid "Destination Port(s)"
msgstr "目标端口"
msgid "Disable QoS"
msgstr "禁用 QoS"
msgid "Download Settings"
msgstr "下载设置"
msgid ""
"Each service class is specified by four parameters: percent bandwidth at "
"capacity, realtime bandwidth and maximum bandwidth and the minimimze round "
"trip time flag."
msgstr ""
"每个下载服务类型由四个参数指定:带宽占用百分比、最小保证带宽、最大带宽和最小"
"往返延时标志。"
msgid ""
"Each upload service class is specified by three parameters: percent "
"bandwidth at capacity, minimum bandwidth and maximum bandwidth."
msgstr "每个上传服务类型由三个参数指定:带宽占用百分比、最小带宽和最大带宽。"
msgid "Edit Download Classification Rule"
msgstr "编辑下载分类规则"
msgid "Edit Download Service Class"
msgstr "编辑下载服务类型"
msgid "Edit Upload Classification Rule"
msgstr "编辑上传分类规则"
msgid "Edit Upload Service Class"
msgstr "编辑上传服务类型"
msgid "Enable Active Congestion Control"
msgstr "启用主动拥塞控制"
msgid "Enable QoS"
msgstr "启用 QoS"
msgid "Error collecting troubleshooting information"
msgstr "收集故障排查信息失败"
msgid "Gargoyle QoS"
msgstr "石像鬼 QoS"
msgid "Global Settings"
msgstr "全局设置"
msgid ""
"Indicates to the active congestion controller that you wish to minimize "
"round trip times (RTT) when this class is active. Use this setting for "
"online gaming or VoIP applications that need low round trip times (ping "
"times). Minimizing RTT comes at the expense of efficient WAN throughput so "
"while these class are active your WAN throughput will decline (usually "
"around 20%)."
msgstr ""
"告诉主动拥塞控制器你希望该服务类型启用时尽量减少往返延时RTT。该设置一般用"
"在 VoIP 或在线游戏这类需要低延时Ping 值的应用上。减小往返延时RTT会带"
"来WAN有效吞吐量的额外花销所以当这些服务类型启用时你的 WAN 吞吐量将下降(通"
"常在20%左右)"
msgid "Load"
msgstr "负载"
msgid "Loading"
msgstr "正在加载"
msgid "Manual Ping Limit"
msgstr "手动 Ping 限制"
msgid "Maximum Bandwidth"
msgstr "最大带宽"
msgid "Maximum Packet Length"
msgstr "最大数据包长度"
msgid "Minimize RTT"
msgstr "最小往返延时"
msgid "Minimum Bandwidth"
msgstr "最小带宽"
msgid "Minimum Packet Length"
msgstr "最小数据包长度"
msgid "No"
msgstr "否"
msgid "No data found"
msgstr "无数据"
msgid "None"
msgstr "无"
msgid "Not set"
msgstr "未设置"
msgid ""
"Packet's destination ip, can optionally have /[mask] after it (see -d option "
"in iptables man page)."
msgstr ""
"数据包的目标 IP可以在后面加子网掩码/[mask],请看 iptables 的 -d 参数说"
"明)"
msgid "Packet's destination port, can be a range (eg. 80-90)."
msgstr "数据包的目标端口可以是一个范围例如80-90"
msgid "Packet's maximum size (in bytes)."
msgstr "数据包的最大大小单位bytes"
msgid "Packet's minimum size (in bytes)."
msgstr "数据包的最小大小单位bytes"
msgid ""
"Packet's source ip, can optionally have /[mask] after it (see -s option in "
"iptables man page)."
msgstr ""
"数据包的源 IP可以在后面加子网掩码/[mask],请看 iptables 的 -s 参数说明)"
msgid "Packet's source port, can be a range (eg. 80-90)."
msgstr "数据包的源端口可以是一个范围例如80-90"
msgid ""
"Packets are tested against the rules in the order specified -- rules toward "
"the top have priority. As soon as a packet matches a rule it is classified, "
"and the rest of the rules are ignored. The order of the rules can be altered "
"using the arrow controls."
msgstr ""
"数据包将按规则中指定的顺序进行匹配 —— 靠上的规则优先进行匹配。一旦数据包匹配"
"一条规则那它将被归类,并且其余的规则将被忽略。使用上下箭头可调整规则的顺序。"
msgid "Percent Bandwidth At Capacity"
msgstr "带宽占用百分比"
msgid "QoS Switch"
msgstr "QoS 开关"
msgid ""
"Quality of Service (QoS) provides a way to control how available bandwidth "
"is allocated."
msgstr "QoS 可以用来分配和控制可用带宽。"
msgid ""
"Round trip ping times are compared against the ping limits. ACC controls the "
"link limit to maintain ping times under the appropriate limit. By default "
"ACC attempts to automatically select appropriate target ping limits for you "
"based on the link speeds you entered and the performance of your link it "
"measures during initialization. You cannot change the target ping time for "
"the minRTT mode but by entering a manual time you can control the target "
"ping time of the active mode. The time you enter becomes the increase in the "
"target ping time between minRTT and active mode. Leave empty to use the "
"default settings."
msgstr ""
"Ping 延时会与 Ping 限制进行比较。ACC 控制链路限制以保持 Ping 延时在适当范围。"
"默认情况下ACC 会自动根据你输入的链接适当为你选择适当的 Ping 限制。如果你想"
"尝试不同的 Ping 限制,你可以在这里输入一个时间值。输入高的时间值将导致更高的 "
"Ping 限制,低的时间值会有更低的限制。留空则将由 ACC 自动控制。"
msgid "Service Class"
msgstr "服务类型"
msgid "Service Class Name"
msgstr "服务类型名称"
msgid "Service Classes"
msgstr "服务类型"
msgid ""
"Should be set to around 98% of your available upload bandwidth. Entering a "
"number which is too high will result in QoS not meeting its class "
"requirements. Entering a number which is too low will needlessly penalize "
"your upload speed. You should use a speed test program (with QoS off) to "
"determine available upload bandwidth. Note that bandwidth is specified in "
"kbps, leave blank to disable update QoS. There are 8 kilobits per kilobyte."
msgstr ""
"应被设置为你可用上传带宽的 98% 左右。输入数值太高将导致 QoS 不能匹配服务类型"
"的要求。输入数值太低将造成不必要的上传速度限制。你应当在 QoS 关闭的情况下使用"
"测速程序以确定可用的上传带宽。带宽以 kbps 为单位,留空以禁用上传 QoS。"
"1KByte/s=8Kbps"
msgid "Source IP(s)"
msgstr "源 IP"
msgid "Source Port(s)"
msgstr "源端口"
msgid "Specifie how packets that do not match any rule should be classified."
msgstr "指定当数据包不匹配任何规则时将被如何归类。"
msgid ""
"Specifying correctly is crucial to making QoS work. Note that bandwidth is "
"specified in kbps, leave blank to disable download QoS. There are 8 kilobits "
"per kilobyte."
msgstr ""
"正确设置对于 QoS 的工作至关重要。带宽以 kbps 为单位,留空以禁用下载 QoS。"
"1KByte/s=8Kbps"
msgid ""
"The maximum amount of bandwidth this class will be allocated in kbit/s. Even "
"if unused bandwidth is available, this service class will never be permitted "
"to use more than this amount of bandwidth."
msgstr ""
"该服务类型可被分配的带宽最大值(以 kbit/s 为单位)。即使存在未使用带宽,该服"
"务类型也将永远不被允许使用超过此量的带宽。"
msgid ""
"The minimum service this class will be allocated when the link is at "
"capacity. Classes which specify minimum service are known as realtime "
"classes by the active congestion controller. Streaming video, VoIP and "
"interactive online gaming are all examples of applications that must have a "
"minimum bandwith to function. To determine what to enter use the application "
"on an unloaded LAN and observe how much bandwidth it uses. Then enter a "
"number only slightly higher than this into this field. QoS will satisfiy the "
"minimum service of all classes first before allocating to other waiting "
"classes so be careful to use minimum bandwidths sparingly."
msgstr ""
"将被分配用于该服务类型的最低链路带宽容量。指定了最小带宽的服务类型会被主动拥"
"塞控制器看作实时类应用。例如视频流、VoIP 和在线互动游戏都应该设置最小带宽。要"
"确定需要多少最小带宽,可以在一个没有负载的局域网中使用应用程序并观察它使用了"
"多少带宽。然后输入一个略高于这个值的数字到字段中。在分配剩余带宽到其它服务类"
"型前QoS 将优先满足所有服务类型的最小带宽要求,所以要谨慎地使用最小带宽。"
msgid ""
"The percentage of the total available bandwidth that should be allocated to "
"this class when all available bandwidth is being used. If unused bandwidth "
"is available, more can (and will) be allocated. The percentages can be "
"configured to equal more (or less) than 100, but when the settings are "
"applied the percentages will be adjusted proportionally so that they add to "
"100. This setting only comes into effect when the WAN link is saturated."
msgstr ""
"当所有可用带宽被占满后该服务类型占据总带宽的百分比。如果带宽未用完,该服务类"
"型会被分配更多带宽。该百分比值可被设置为等于、大于或小于 100但当设置被应用"
"时,百分比值将会被按比例调整以便使它们加起来等于 100。该设置只在 WAN 端链路饱"
"和时才生效。<em>PSWAN 端链路饱和即带宽被占用完)</em>"
msgid ""
"The segment of network between your router and the ping target is where "
"congestion is controlled. By monitoring the round trip ping times to the "
"target congestion is detected. By default ACC uses your WAN gateway as the "
"ping target. If you know that congestion on your link will occur in a "
"different segment then you can enter an alternate ping target. Leave empty "
"to use the default settings."
msgstr ""
"在路由器和 Ping 目标之间的网络部分是拥塞控制的地方。拥塞通过监视和目标间的 "
"Ping 延时来检测。默认情况下 ACC 使用你的 WAN 网关作为 Ping 的目标。假如你知道"
"拥塞会在你链路的不同段发生,你可用输入一个备用的 Ping 目标。留空则将由ACC 自"
"动控制。"
msgid ""
"The total size of data transmitted since the establishment of the link (in "
"kBytes)."
msgstr "自连接建立以来传输的数据总量单位kBytes"
msgid "Total Download Bandwidth"
msgstr "下载总带宽"
msgid "Total Upload Bandwidth"
msgstr "上传总带宽"
msgid "Transport Protocol"
msgstr "协议"
msgid "Troubleshooting"
msgstr "故障排除"
msgid "Troubleshooting Data"
msgstr "故障排除数据"
msgid "Unlimited"
msgstr "不限制"
msgid "Upload Settings"
msgstr "上传设置"
msgid "Use Non-standard Ping Target"
msgstr "使用自定义 Ping 目标"
msgid "Zero"
msgstr "零"

View File

@ -0,0 +1,11 @@
#!/bin/sh
uci -q batch <<-EOF >/dev/null
delete ucitrack.@qos_gargoyle[-1]
add ucitrack qos_gargoyle
set ucitrack.@qos_gargoyle[-1].init=qos_gargoyle
commit ucitrack
EOF
rm -rf /tmp/luci-modulecache /tmp/luci-indexcache
exit 0