sqm-cbi.lua 10 KB

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