interface.lua 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. -- Copyright 2014 Aedan Renner <chipdankly@gmail.com
  2. -- Copyright 2018 Florian Eckert <fe@dev.tdt.de>
  3. -- Licensed to the public under the GNU General Public License v2.
  4. dsp = require "luci.dispatcher"
  5. uci = require "uci"
  6. function interfaceWarnings(overview, count, iface_max)
  7. local warnings = ""
  8. if count <= iface_max then
  9. warnings = string.format("<strong>%s</strong><br />",
  10. translatef("There are currently %d of %d supported interfaces configured", count, iface_max)
  11. )
  12. else
  13. warnings = string.format("<strong>%s</strong><br />",
  14. translatef("WARNING: %d interfaces are configured exceeding the maximum of %d!", count, iface_max)
  15. )
  16. end
  17. for i, k in pairs(overview) do
  18. if overview[i]["network"] == false then
  19. warnings = warnings .. string.format("<strong>%s</strong><br />",
  20. translatef("WARNING: Interface %s are not found in /etc/config/network", i)
  21. )
  22. end
  23. if overview[i]["default_route"] == false then
  24. warnings = warnings .. string.format("<strong>%s</strong><br />",
  25. translatef("WARNING: Interface %s has no default route in the main routing table", i)
  26. )
  27. end
  28. if overview[i]["reliability"] == false then
  29. warnings = warnings .. string.format("<strong>%s</strong><br />",
  30. translatef("WARNING: Interface %s has a higher reliability " ..
  31. "requirement than tracking hosts (%d)", i, overview[i]["tracking"])
  32. )
  33. end
  34. if overview[i]["duplicate_metric"] == true then
  35. warnings = warnings .. string.format("<strong>%s</strong><br />",
  36. translatef("WARNING: Interface %s has a duplicate metric %s configured", i, overview[i]["metric"])
  37. )
  38. end
  39. end
  40. return warnings
  41. end
  42. function configCheck()
  43. local overview = {}
  44. local count = 0
  45. local duplicate_metric = {}
  46. uci.cursor():foreach("mwan3", "interface",
  47. function (section)
  48. local uci = uci.cursor(nil, "/var/state")
  49. local iface = section[".name"]
  50. overview[iface] = {}
  51. count = count + 1
  52. local network = uci:get("network", iface)
  53. overview[iface]["network"] = false
  54. if network ~= nil then
  55. overview[iface]["network"] = true
  56. local device = uci:get("network", iface, "ifname")
  57. if device ~= nil then
  58. overview[iface]["device"] = device
  59. end
  60. local metric = uci:get("network", iface, "metric")
  61. if metric ~= nil then
  62. overview[iface]["metric"] = metric
  63. overview[iface]["duplicate_metric"] = false
  64. for _, m in ipairs(duplicate_metric) do
  65. if m == metric then
  66. overview[iface]["duplicate_metric"] = true
  67. end
  68. end
  69. table.insert(duplicate_metric, metric)
  70. end
  71. local dump = require("luci.util").ubus("network.interface.%s" % iface, "status", {})
  72. overview[iface]["default_route"] = false
  73. if dump and dump.route then
  74. local _, route
  75. for _, route in ipairs(dump.route) do
  76. if dump.route[_].target == "0.0.0.0" then
  77. overview[iface]["default_route"] = true
  78. end
  79. end
  80. end
  81. end
  82. local trackingNumber = uci:get("mwan3", iface, "track_ip")
  83. overview[iface]["tracking"] = 0
  84. if trackingNumber and #trackingNumber > 0 then
  85. overview[iface]["tracking"] = #trackingNumber
  86. overview[iface]["reliability"] = false
  87. local reliabilityNumber = tonumber(uci:get("mwan3", iface, "reliability"))
  88. if reliabilityNumber and reliabilityNumber <= #trackingNumber then
  89. overview[iface]["reliability"] = true
  90. end
  91. end
  92. end
  93. )
  94. -- calculate iface_max usage from firewall mmx_mask
  95. function bit(p)
  96. return 2 ^ (p - 1)
  97. end
  98. function hasbit(x, p)
  99. return x % (p + p) >= p
  100. end
  101. function setbit(x, p)
  102. return hasbit(x, p) and x or x + p
  103. end
  104. local uci = require("uci").cursor(nil, "/var/state")
  105. local mmx_mask = uci:get("mwan3", "globals", "mmx_mask") or "0x3F00"
  106. local number = tonumber(mmx_mask, 16)
  107. local bits = 0
  108. local iface_max = 0
  109. for i=1,16 do
  110. if hasbit(number, bit(i)) then
  111. bits = bits + 1
  112. iface_max = setbit( iface_max, bit(bits))
  113. end
  114. end
  115. -- subtract blackhole, unreachable and default table from iface_max
  116. iface_max = iface_max - 3
  117. return overview, count, iface_max
  118. end
  119. m5 = Map("mwan3", translate("MWAN - Interfaces"),
  120. interfaceWarnings(configCheck()))
  121. mwan_interface = m5:section(TypedSection, "interface", nil,
  122. translate("MWAN supports up to 252 physical and/or logical interfaces<br />" ..
  123. "MWAN requires that all interfaces have a unique metric configured in /etc/config/network<br />" ..
  124. "Names must match the interface name found in /etc/config/network<br />" ..
  125. "Names may contain characters A-Z, a-z, 0-9, _ and no spaces<br />" ..
  126. "Interfaces may not share the same name as configured members, policies or rules"))
  127. mwan_interface.addremove = true
  128. mwan_interface.dynamic = false
  129. mwan_interface.sectionhead = translate("Interface")
  130. mwan_interface.sortable = false
  131. mwan_interface.template = "cbi/tblsection"
  132. mwan_interface.extedit = dsp.build_url("admin", "network", "mwan", "interface", "%s")
  133. function mwan_interface.create(self, section)
  134. TypedSection.create(self, section)
  135. m5.uci:save("mwan3")
  136. luci.http.redirect(dsp.build_url("admin", "network", "mwan", "interface", section))
  137. end
  138. enabled = mwan_interface:option(DummyValue, "enabled", translate("Enabled"))
  139. enabled.rawhtml = true
  140. function enabled.cfgvalue(self, s)
  141. if self.map:get(s, "enabled") == "1" then
  142. return translate("Yes")
  143. else
  144. return translate("No")
  145. end
  146. end
  147. track_method = mwan_interface:option(DummyValue, "track_method", translate("Tracking method"))
  148. track_method.rawhtml = true
  149. function track_method.cfgvalue(self, s)
  150. local tracked = self.map:get(s, "track_ip")
  151. if tracked then
  152. return self.map:get(s, "track_method") or "ping"
  153. else
  154. return "&#8212;"
  155. end
  156. end
  157. reliability = mwan_interface:option(DummyValue, "reliability", translate("Tracking reliability"))
  158. reliability.rawhtml = true
  159. function reliability.cfgvalue(self, s)
  160. local tracked = self.map:get(s, "track_ip")
  161. if tracked then
  162. return self.map:get(s, "reliability") or "1"
  163. else
  164. return "&#8212;"
  165. end
  166. end
  167. interval = mwan_interface:option(DummyValue, "interval", translate("Ping interval"))
  168. interval.rawhtml = true
  169. function interval.cfgvalue(self, s)
  170. local tracked = self.map:get(s, "track_ip")
  171. if tracked then
  172. local intervalValue = self.map:get(s, "interval")
  173. if intervalValue then
  174. return intervalValue .. "s"
  175. else
  176. return "5s"
  177. end
  178. else
  179. return "&#8212;"
  180. end
  181. end
  182. down = mwan_interface:option(DummyValue, "down", translate("Interface down"))
  183. down.rawhtml = true
  184. function down.cfgvalue(self, s)
  185. local tracked = self.map:get(s, "track_ip")
  186. if tracked then
  187. return self.map:get(s, "down") or "3"
  188. else
  189. return "&#8212;"
  190. end
  191. end
  192. up = mwan_interface:option(DummyValue, "up", translate("Interface up"))
  193. up.rawhtml = true
  194. function up.cfgvalue(self, s)
  195. local tracked = self.map:get(s, "track_ip")
  196. if tracked then
  197. return self.map:get(s, "up") or "3"
  198. else
  199. return "&#8212;"
  200. end
  201. end
  202. metric = mwan_interface:option(DummyValue, "metric", translate("Metric"))
  203. metric.rawhtml = true
  204. function metric.cfgvalue(self, s)
  205. local uci = uci.cursor(nil, "/var/state")
  206. local metric = uci:get("network", s, "metric")
  207. if metric then
  208. return metric
  209. else
  210. return "&#8212;"
  211. end
  212. end
  213. return m5