luci-app-sqm: move from packages feed
[oweals/luci.git] / applications / luci-app-sqm / luasrc / model / cbi / sqm.lua
1 --[[
2 LuCI - Lua Configuration Interface
3
4 Copyright 2014 Steven Barth <steven@midlink.org>
5 Copyright 2014 Dave Taht <dave.taht@bufferbloat.net>
6
7 Licensed under the Apache License, Version 2.0 (the "License");
8 you may not use this file except in compliance with the License.
9 You may obtain a copy of the License at
10
11         http://www.apache.org/licenses/LICENSE-2.0
12
13 $Id$
14 ]]--
15
16 local wa = require "luci.tools.webadmin"
17 local fs = require "nixio.fs"
18 local net = require "luci.model.network".init()
19 local sys = require "luci.sys"
20 --local ifaces = net:get_interfaces()
21 local ifaces = sys.net:devices()
22 local path = "/usr/lib/sqm"
23 local run_path = "/tmp/run/sqm/available_qdiscs"
24
25 m = Map("sqm", translate("Smart Queue Management"),
26         translate("With <abbr title=\"Smart Queue Management\">SQM</abbr> you " ..
27                   "can enable traffic shaping, better mixing (Fair Queueing)," ..
28                   " active queue length management (AQM) " ..
29                   " and prioritisation on one " ..
30                   "network interface."))
31
32 s = m:section(TypedSection, "queue", translate("Queues"))
33 s:tab("tab_basic", translate("Basic Settings"))
34 s:tab("tab_qdisc", translate("Queue Discipline"))
35 s:tab("tab_linklayer", translate("Link Layer Adaptation"))
36 s.addremove = true -- set to true to allow adding SQM instances in the GUI
37 s.anonymous = true
38
39 -- BASIC
40 e = s:taboption("tab_basic", Flag, "enabled", translate("Enable this SQM instance."))
41 e.rmempty = false
42
43 -- sm: following jow's advise, be helpful to the user and enable
44 --     sqm's init script if even a single sm instance/interface
45 --     is enabled; this is unexpected in that the init script gets
46 --     enabled as soon as at least one sqm instance is enabled
47 --     and that state is saved, so it does not require "Save & Apply"
48 --     to effect the init scripts.
49 --     the implementation was inpired/lifted from 
50 --     https://github.com/openwrt/luci/blob/master/applications/luci-app-minidlna/luasrc/model/cbi/minidlna.lua
51 function e.write(self, section, value)
52         if value == "1" then
53                 luci.sys.init.enable("sqm")
54                 m.message = translate("The SQM GUI has just enabled the sqm initscript on your behalf. Remember to disable the sqm initscript manually under System Startup menu in case this change was not wished for.")
55         end
56         return Flag.write(self, section, value)
57 end
58 -- TODO: inform the user what we just did...
59
60
61 -- Add to physical interface list a hint of the correpsonding network names,
62 -- used to help users better select e.g. lan or wan interface.
63
64 n = s:taboption("tab_basic", ListValue, "interface", translate("Interface name"))
65 -- sm lifted from luci-app-wol, the original implementation failed to show pppoe-ge00 type interface names
66 for _, iface in ipairs(ifaces) do
67         if not (iface == "lo" or iface:match("^ifb.*")) then
68                 local nets = net:get_interface(iface)
69                 nets = nets and nets:get_networks() or {}
70                 for k, v in pairs(nets) do
71                         nets[k] = nets[k].sid
72                 end
73                 nets = table.concat(nets, ",")
74                 n:value(iface, ((#nets > 0) and "%s (%s)" % {iface, nets} or iface))
75         end
76 end
77 n.rmempty = false
78
79
80 dl = s:taboption("tab_basic", Value, "download", translate("Download speed (kbit/s) (ingress) set to 0 to selectively disable ingress shaping:"))
81 dl.datatype = "and(uinteger,min(0))"
82 dl.rmempty = false
83
84 ul = s:taboption("tab_basic", Value, "upload", translate("Upload speed (kbit/s) (egress) set to 0 to selectively disable egress shaping:"))
85 ul.datatype = "and(uinteger,min(0))"
86 ul.rmempty = false
87
88 dbl = s:taboption("tab_basic", Flag, "debug_logging", translate("Create log file for this SQM instance under /var/run/sqm/${Interface_name}.[start|stop]-sqm.log."))
89 dbl.rmempty = false
90
91
92 verb = s:taboption("tab_basic", ListValue, "verbosity", translate("Verbosity of SQM's output into the system log."))
93 verb:value("0", "silent")
94 verb:value("1", "error")
95 verb:value("2", "warning")
96 verb:value("5", "info ("..translate("default")..")")
97 verb:value("8", "debug")
98 verb:value("10", "trace")
99 verb.default = "5"
100 verb.rmempty = true
101
102
103
104
105 -- QDISC
106
107 local val_qdisc_name = ""
108 c = s:taboption("tab_qdisc", ListValue, "qdisc", translate("Queuing disciplines useable on this system. After installing a new qdisc, you need to restart the router to see updates!"))
109 c:value("fq_codel", "fq_codel ("..translate("default")..")")
110
111 if fs.stat(run_path) then
112         for file in fs.dir(run_path) do
113                 c:value( file )
114         end
115 end
116 c.default = "fq_codel"
117 c.rmempty = false
118
119
120
121 local qos_desc = ""
122 sc = s:taboption("tab_qdisc", ListValue, "script", translate("Queue setup script"))
123 for file in fs.dir(path) do
124         if string.find(file, ".qos$") and not fs.stat(path .. "/" .. file .. ".hidden") then
125                 sc:value(file)
126                 qos_desc = qos_desc .. "<p><b>" .. file .. ":</b><br />"
127                 fh = io.open(path .. "/" .. file .. ".help", "r")
128                 if fh then
129                         qos_desc = qos_desc .. fh:read("*a") .. "</p>"
130                 else
131                         qos_desc = qos_desc .. "No help text</p>"
132                 end
133         end
134 end
135 sc.default = "simple.qos"
136 sc.rmempty = false
137 sc.description = qos_desc
138
139 ad = s:taboption("tab_qdisc", Flag, "qdisc_advanced", translate("Show and Use Advanced Configuration. Advanced options will only be used as long as this box is checked."))
140 ad.default = false
141 ad.rmempty = true
142
143 squash_dscp  = s:taboption("tab_qdisc", ListValue, "squash_dscp", translate("Squash DSCP on inbound packets (ingress):"))
144 squash_dscp:value("1", "SQUASH")
145 squash_dscp:value("0", "DO NOT SQUASH")
146 squash_dscp.default = "1"
147 squash_dscp.rmempty = true
148 squash_dscp:depends("qdisc_advanced", "1")
149
150 squash_ingress = s:taboption("tab_qdisc", ListValue, "squash_ingress", translate("Ignore DSCP on ingress:"))
151 squash_ingress:value("1", "Ignore")
152 squash_ingress:value("0", "Allow")
153 squash_ingress.default = "1"
154 squash_ingress.rmempty = true
155 squash_ingress:depends("qdisc_advanced", "1")
156
157 iecn = s:taboption("tab_qdisc", ListValue, "ingress_ecn", translate("Explicit congestion notification (ECN) status on inbound packets (ingress):"))
158 iecn:value("ECN", "ECN ("..translate("default")..")")
159 iecn:value("NOECN")
160 iecn.default = "ECN"
161 iecn.rmempty = true
162 iecn:depends("qdisc_advanced", "1")
163
164 eecn = s:taboption("tab_qdisc", ListValue, "egress_ecn", translate("Explicit congestion notification (ECN) status on outbound packets (egress)."))
165 eecn:value("NOECN", "NOECN ("..translate("default")..")")
166 eecn:value("ECN")
167 eecn.default = "NOECN"
168 eecn.rmempty = true
169 eecn:depends("qdisc_advanced", "1")
170
171 ad2 = s:taboption("tab_qdisc", Flag, "qdisc_really_really_advanced", translate("Show and Use Dangerous Configuration. Dangerous options will only be used as long as this box is checked."))
172 ad2.default = false
173 ad2.rmempty = true
174 ad2:depends("qdisc_advanced", "1")
175
176 ilim = s:taboption("tab_qdisc", Value, "ilimit", translate("Hard limit on ingress queues; leave empty for default."))
177 -- ilim.default = 1000
178 ilim.isnumber = true
179 ilim.datatype = "and(uinteger,min(0))"
180 ilim.rmempty = true
181 ilim:depends("qdisc_really_really_advanced", "1")
182
183 elim = s:taboption("tab_qdisc", Value, "elimit", translate("Hard limit on egress queues; leave empty for default."))
184 -- elim.default = 1000
185 elim.datatype = "and(uinteger,min(0))"
186 elim.rmempty = true
187 elim:depends("qdisc_really_really_advanced", "1")
188
189
190 itarg = s:taboption("tab_qdisc", Value, "itarget", translate("Latency target for ingress, e.g 5ms [units: s, ms, or  us]; leave empty for automatic selection, put in the word default for the qdisc's default."))
191 itarg.datatype = "string"
192 itarg.rmempty = true
193 itarg:depends("qdisc_really_really_advanced", "1")
194
195 etarg = s:taboption("tab_qdisc", Value, "etarget", translate("Latency target for egress, e.g. 5ms [units: s, ms, or  us]; leave empty for automatic selection, put in the word default for the qdisc's default."))
196 etarg.datatype = "string"
197 etarg.rmempty = true
198 etarg:depends("qdisc_really_really_advanced", "1")
199
200
201
202 iqdisc_opts = s:taboption("tab_qdisc", Value, "iqdisc_opts", translate("Advanced option string to pass to the ingress queueing disciplines; no error checking, use very carefully."))
203 iqdisc_opts.rmempty = true
204 iqdisc_opts:depends("qdisc_really_really_advanced", "1")
205
206 eqdisc_opts = s:taboption("tab_qdisc", Value, "eqdisc_opts", translate("Advanced option string to pass to the egress queueing disciplines; no error checking, use very carefully."))
207 eqdisc_opts.rmempty = true
208 eqdisc_opts:depends("qdisc_really_really_advanced", "1")
209
210 -- LINKLAYER
211 ll = s:taboption("tab_linklayer", ListValue, "linklayer", translate("Which link layer to account for:"))
212 ll:value("none", "none ("..translate("default")..")")
213 ll:value("ethernet", "Ethernet with overhead: select for e.g. VDSL2.")
214 ll:value("atm", "ATM: select for e.g. ADSL1, ADSL2, ADSL2+.")
215 ll.default = "none"
216
217 po = s:taboption("tab_linklayer", Value, "overhead", translate("Per Packet Overhead (byte):"))
218 po.datatype = "and(integer,min(-1500))"
219 po.default = 0
220 po.isnumber = true
221 po.rmempty = true
222 po:depends("linklayer", "ethernet")
223 po:depends("linklayer", "atm")
224
225
226 adll = s:taboption("tab_linklayer", Flag, "linklayer_advanced", translate("Show Advanced Linklayer Options, (only needed if MTU > 1500). Advanced options will only be used as long as this box is checked."))
227 adll.rmempty = true
228 adll:depends("linklayer", "ethernet")
229 adll:depends("linklayer", "atm")
230
231 smtu = s:taboption("tab_linklayer", Value, "tcMTU", translate("Maximal Size for size and rate calculations, tcMTU (byte); needs to be >= interface MTU + overhead:"))
232 smtu.datatype = "and(uinteger,min(0))"
233 smtu.default = 2047
234 smtu.isnumber = true
235 smtu.rmempty = true
236 smtu:depends("linklayer_advanced", "1")
237
238 stsize = s:taboption("tab_linklayer", Value, "tcTSIZE", translate("Number of entries in size/rate tables, TSIZE; for ATM choose TSIZE = (tcMTU + 1) / 16:"))
239 stsize.datatype = "and(uinteger,min(0))"
240 stsize.default = 128
241 stsize.isnumber = true
242 stsize.rmempty = true
243 stsize:depends("linklayer_advanced", "1")
244
245 smpu = s:taboption("tab_linklayer", Value, "tcMPU", translate("Minimal packet size, MPU (byte); needs to be > 0 for ethernet size tables:"))
246 smpu.datatype = "and(uinteger,min(0))"
247 smpu.default = 0
248 smpu.isnumber = true
249 smpu.rmempty = true
250 smpu:depends("linklayer_advanced", "1")
251
252 lla = s:taboption("tab_linklayer", ListValue, "linklayer_adaptation_mechanism", translate("Which linklayer adaptation mechanism to use; for testing only"))
253 lla:value("default", "default ("..translate("default")..")")
254 lla:value("cake")
255 lla:value("htb_private")
256 lla:value("tc_stab")
257 lla.default = "default"
258 lla.rmempty = true
259 lla:depends("linklayer_advanced", "1")
260
261 -- PRORITIES?
262
263 return m