Merge pull request #1561 from TDT-AG/pr/luci-app-mwan3-refactoring-continue

luci-app-mwan3: refactoring continue 2
This commit is contained in:
Hannu Nyman 2018-01-18 16:43:49 +02:00 committed by GitHub
commit cf1af792d6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 823 additions and 1316 deletions

View file

@ -23,7 +23,7 @@ function index()
entry({"admin", "status", "mwan", "troubleshooting"}, entry({"admin", "status", "mwan", "troubleshooting"},
template("mwan/status_troubleshooting")) template("mwan/status_troubleshooting"))
entry({"admin", "status", "mwan", "interface_status"}, entry({"admin", "status", "mwan", "interface_status"},
call("interfaceStatus")) call("mwan_Status"))
entry({"admin", "status", "mwan", "detailed_status"}, entry({"admin", "status", "mwan", "detailed_status"},
call("detailedStatus")) call("detailedStatus"))
entry({"admin", "status", "mwan", "diagnostics_display"}, entry({"admin", "status", "mwan", "diagnostics_display"},
@ -56,83 +56,31 @@ function index()
_("Notification"), 50).leaf = true _("Notification"), 50).leaf = true
end end
function getInterfaceStatus(ruleNumber, interfaceName) function mwan_Status()
if ut.trim(sys.exec("uci -q -p /var/state get mwan3." .. interfaceName .. ".enabled")) == "1" then local status = ut.ubus("mwan3", "status", {})
if ut.trim(sys.exec(ip .. "route list table " .. ruleNumber)) ~= "" then
if ut.trim(sys.exec("uci -q -p /var/state get mwan3." .. interfaceName .. ".track_ip")) ~= "" then
return "online"
else
return "notMonitored"
end
else
return "offline"
end
else
return "notEnabled"
end
end
function getInterfaceName()
local ruleNumber, status = 0, ""
uci.cursor():foreach("mwan3", "interface",
function (section)
ruleNumber = ruleNumber+1
status = status .. section[".name"] .. "[" .. getInterfaceStatus(ruleNumber, section[".name"]) .. "]"
end
)
return status
end
function interfaceStatus()
local ntm = require "luci.model.network".init()
local mArray = {}
-- overview status
local statusString = getInterfaceName()
if statusString ~= "" then
mArray.wans = {}
wansid = {}
for wanName, interfaceState in string.gfind(statusString, "([^%[]+)%[([^%]]+)%]") do
local wanInterfaceName = ut.trim(sys.exec("uci -q -p /var/state get network." .. wanName .. ".ifname"))
if wanInterfaceName == "" then
wanInterfaceName = "X"
end
local wanDeviceLink = ntm:get_interface(wanInterfaceName)
wanDeviceLink = wanDeviceLink and wanDeviceLink:get_network()
wanDeviceLink = wanDeviceLink and wanDeviceLink:adminlink() or "#"
wansid[wanName] = #mArray.wans + 1
mArray.wans[wansid[wanName]] = { name = wanName, link = wanDeviceLink, ifname = wanInterfaceName, status = interfaceState }
end
end
-- overview status log
local mwanLog = ut.trim(sys.exec("logread | grep mwan3 | tail -n 50 | sed 'x;1!H;$!d;x' 2>/dev/null"))
if mwanLog ~= "" then
mArray.mwanlog = { mwanLog }
end
luci.http.prepare_content("application/json") luci.http.prepare_content("application/json")
luci.http.write_json(mArray) if status ~= nil then
luci.http.write_json(status)
else
luci.http.write_json({})
end
end end
function detailedStatus() function detailedStatus()
local mArray = {} local statusInfo = ut.trim(sys.exec("/usr/sbin/mwan3 status"))
luci.http.prepare_content("text/plain")
-- detailed mwan status if statusInfo ~= "" then
local detailStatusInfo = ut.trim(sys.exec("/usr/sbin/mwan3 status")) luci.http.write(statusInfo)
if detailStatusInfo ~= "" then else
mArray.mwandetail = { detailStatusInfo } luci.http.write("Unable to get status information")
end end
luci.http.prepare_content("application/json")
luci.http.write_json(mArray)
end end
function diagnosticsData(interface, tool, task) function diagnosticsData(interface, task)
function getInterfaceNumber() function getInterfaceNumber(interface)
local number = 0 local number = 0
local interfaceNumber
uci.cursor():foreach("mwan3", "interface", uci.cursor():foreach("mwan3", "interface",
function (section) function (section)
number = number+1 number = number+1
@ -141,184 +89,213 @@ function diagnosticsData(interface, tool, task)
end end
end end
) )
return interfaceNumber
end
function diag_command(cmd, addr)
if addr and addr:match("^[a-zA-Z0-9%-%.:_]+$") then
local util = io.popen(cmd % addr)
if util then
while true do
local ln = util:read("*l")
if not ln then break end
luci.http.write(ln)
luci.http.write("\n")
end
util:close()
end
return
end
end
function get_gateway(inteface)
local dump = require("luci.util").ubus("network.interface.%s" % interface, "status", {})
local gateway
if dump then
local _, route
for _, route in ipairs(dump.route) do
if dump.route[_].target == "0.0.0.0" then
gateway = dump.route[_].nexthop
end
end
end
return gateway
end end
local mArray = {} local mArray = {}
local results = "" local results = ""
if tool == "service" then local number = getInterfaceNumber(interface)
os.execute("/usr/sbin/mwan3 " .. task)
if task == "restart" then local uci = uci.cursor(nil, "/var/state")
results = "MWAN3 restarted" local device = uci:get("network", interface, "ifname")
elseif task == "stop" then
results = "MWAN3 stopped" luci.http.prepare_content("text/plain")
if device ~= "" then
if task == "ping_gateway" then
local gateway = get_gateway(interface)
if gateway ~= nil then
diag_command("ping -c 5 -W 1 %q 2>&1", gateway)
else
luci.http.prepare_content("text/plain")
luci.http.write(string.format("No gateway for interface %s found.", interface))
end
elseif task == "ping_trackips" then
local trackips = uci:get("mwan3", interface, "track_ip")
if #trackips > 0 then
for i in pairs(trackips) do
diag_command("ping -c 5 -W 1 %q 2>&1", trackips[i])
end
else
luci.http.write(string.format("No tracking Hosts for interface %s defined.", interface))
end
elseif task == "check_rules" then
local number = getInterfaceNumber(interface)
local iif = 1000 + number
local fwmark = 2000 + number
local iif_rule = sys.exec(string.format("ip rule | grep %d", iif))
local fwmark_rule = sys.exec(string.format("ip rule | grep %d", fwmark))
if iif_rule ~= "" and fwmark_rule ~= "" then
luci.http.write(string.format("All required IP rules for interface %s found", interface))
luci.http.write("\n")
luci.http.write(fwmark_rule)
luci.http.write(iif_rule)
elseif iif_rule == "" and fwmark_rule ~= "" then
luci.http.write(string.format("Only one IP rules for interface %s found", interface))
luci.http.write("\n")
luci.http.write(fwmark_rule)
elseif iif_rule ~= "" and fwmark_rule == "" then
luci.http.write(string.format("Only one IP rules for interface %s found", interface))
luci.http.write("\n")
luci.http.write(iif_rule)
else
luci.http.write(string.format("Missing both IP rules for interface %s", interface))
end
elseif task == "check_routes" then
local number = getInterfaceNumber(interface)
local routeTable = sys.exec(string.format("ip route list table %s", number))
if routeTable ~= "" then
luci.http.write(string.format("Routing table %s for interface %s found", number, interface))
luci.http.write("\n")
luci.http.write(routeTable)
else
luci.http.write(string.format("Routing table %s for interface %s not found", number, interface))
end
elseif task == "hotplug_ifup" then
os.execute(string.format("/usr/sbin/mwan3 ifup %s", interface))
luci.http.write(string.format("Hotplug ifup sent to interface %s", interface))
elseif task == "hotplug_ifdown" then
os.execute(string.format("/usr/sbin/mwan3 ifdown %s", interface))
luci.http.write(string.format("Hotplug ifdown sent to interface %s", interface))
else else
results = "MWAN3 started" luci.http.write("Unknown task")
end end
else else
local interfaceDevice = ut.trim(sys.exec("uci -q -p /var/state get network." .. interface .. ".ifname")) luci.http.write(string.format("Unable to perform diagnostic tests on %s.", interface))
if interfaceDevice ~= "" then luci.http.write("\n")
if tool == "ping" then luci.http.write("There is no physical or virtual device associated with this interface.")
local gateway = ut.trim(sys.exec("route -n | awk '{if ($8 == \"" .. interfaceDevice .. "\" && $1 == \"0.0.0.0\" && $3 == \"0.0.0.0\") print $2}'"))
if gateway ~= "" then
if task == "gateway" then
local pingCommand = "ping -c 3 -W 2 -I " .. interfaceDevice .. " " .. gateway
results = pingCommand .. "\n\n" .. sys.exec(pingCommand)
else
local tracked = ut.trim(sys.exec("uci -q -p /var/state get mwan3." .. interface .. ".track_ip"))
if tracked ~= "" then
for z in tracked:gmatch("[^ ]+") do
local pingCommand = "ping -c 3 -W 2 -I " .. interfaceDevice .. " " .. z
results = results .. pingCommand .. "\n\n" .. sys.exec(pingCommand) .. "\n\n"
end
else
results = "No tracking IP addresses configured on " .. interface
end
end
else
results = "No default gateway for " .. interface .. " found. Default route does not exist or is configured incorrectly"
end
elseif tool == "rulechk" then
getInterfaceNumber()
local rule1 = sys.exec(ip .. "rule | grep $(echo $((" .. interfaceNumber .. " + 1000)))")
local rule2 = sys.exec(ip .. "rule | grep $(echo $((" .. interfaceNumber .. " + 2000)))")
if rule1 ~= "" and rule2 ~= "" then
results = "All required interface IP rules found:\n\n" .. rule1 .. rule2
elseif rule1 ~= "" or rule2 ~= "" then
results = "Missing 1 of the 2 required interface IP rules\n\n\nRules found:\n\n" .. rule1 .. rule2
else
results = "Missing both of the required interface IP rules"
end
elseif tool == "routechk" then
getInterfaceNumber()
local routeTable = sys.exec(ip .. "route list table " .. interfaceNumber)
if routeTable ~= "" then
results = "Interface routing table " .. interfaceNumber .. " was found:\n\n" .. routeTable
else
results = "Missing required interface routing table " .. interfaceNumber
end
elseif tool == "hotplug" then
if task == "ifup" then
os.execute("/usr/sbin/mwan3 ifup " .. interface)
results = "Hotplug ifup sent to interface " .. interface .. "..."
else
os.execute("/usr/sbin/mwan3 ifdown " .. interface)
results = "Hotplug ifdown sent to interface " .. interface .. "..."
end
end
else
results = "Unable to perform diagnostic tests on " .. interface .. ". There is no physical or virtual device associated with this interface"
end
end end
if results ~= "" then
results = ut.trim(results)
mArray.diagnostics = { results }
end
luci.http.prepare_content("application/json")
luci.http.write_json(mArray)
end end
function troubleshootingData() function troubleshootingData()
local ver = require "luci.version" local ver = require "luci.version"
local dash = "-------------------------------------------------"
local mArray = {} luci.http.prepare_content("text/plain")
-- software versions luci.http.write("\n")
local wrtRelease = ut.trim(ver.distversion) luci.http.write("\n")
if wrtRelease ~= "" then luci.http.write("Software-Version")
wrtRelease = "OpenWrt - " .. wrtRelease luci.http.write("\n")
else luci.http.write(dash)
wrtRelease = "OpenWrt - unknown" luci.http.write("\n")
end if ver.distversion then
local luciRelease = ut.trim(ver.luciversion) luci.http.write(string.format("OpenWrt - %s", ver.distversion))
if luciRelease ~= "" then luci.http.write("\n")
luciRelease = "\nLuCI - " .. luciRelease else
else luci.http.write("OpenWrt - unknown")
luciRelease = "\nLuCI - unknown" luci.http.write("\n")
end end
local mwanVersion = ut.trim(sys.exec("opkg info mwan3 | grep Version | awk '{print $2}'"))
if mwanVersion ~= "" then
mwanVersion = "\n\nmwan3 - " .. mwanVersion
else
mwanVersion = "\n\nmwan3 - unknown"
end
local mwanLuciVersion = ut.trim(sys.exec("opkg info luci-app-mwan3 | grep Version | awk '{print $2}'"))
if mwanLuciVersion ~= "" then
mwanLuciVersion = "\nmwan3-luci - " .. mwanLuciVersion
else
mwanLuciVersion = "\nmwan3-luci - unknown"
end
mArray.versions = { wrtRelease .. luciRelease .. mwanVersion .. mwanLuciVersion }
-- mwan config if ver.luciversion then
local mwanConfig = ut.trim(sys.exec("cat /etc/config/mwan3")) luci.http.write(string.format("LuCI - %s", ver.luciversion))
if mwanConfig == "" then luci.http.write("\n")
mwanConfig = "No data found" else
end luci.http.write("LuCI - unknown")
mArray.mwanconfig = { mwanConfig } luci.http.write("\n")
end
-- network config luci.http.write("\n")
local networkConfig = ut.trim(sys.exec("cat /etc/config/network | sed -e 's/.*username.*/ USERNAME HIDDEN/' -e 's/.*password.*/ PASSWORD HIDDEN/'")) luci.http.write("\n")
if networkConfig == "" then local output = ut.trim(sys.exec("ip a show"))
networkConfig = "No data found" luci.http.write("Output of \"ip a show\"")
end luci.http.write("\n")
mArray.netconfig = { networkConfig } luci.http.write(dash)
luci.http.write("\n")
if output ~= "" then
luci.http.write(output)
luci.http.write("\n")
else
luci.http.write("No data found")
luci.http.write("\n")
end
-- wireless config luci.http.write("\n")
local wirelessConfig = ut.trim(sys.exec("cat /etc/config/wireless | sed -e 's/.*username.*/ USERNAME HIDDEN/' -e 's/.*password.*/ PASSWORD HIDDEN/' -e 's/.*key.*/ KEY HIDDEN/'")) luci.http.write("\n")
if wirelessConfig == "" then local output = ut.trim(sys.exec("ip route show"))
wirelessConfig = "No data found" luci.http.write("Output of \"ip route show\"")
end luci.http.write("\n")
mArray.wificonfig = { wirelessConfig } luci.http.write(dash)
luci.http.write("\n")
if output ~= "" then
luci.http.write(output)
luci.http.write("\n")
else
luci.http.write("No data found")
luci.http.write("\n")
end
-- ifconfig luci.http.write("\n")
local ifconfig = ut.trim(sys.exec("ifconfig")) luci.http.write("\n")
if ifconfig == "" then local output = ut.trim(sys.exec("ip rule show"))
ifconfig = "No data found" luci.http.write("Output of \"ip rule show\"")
end luci.http.write("\n")
mArray.ifconfig = { ifconfig } luci.http.write(dash)
luci.http.write("\n")
if output ~= "" then
luci.http.write(output)
luci.http.write("\n")
else
luci.http.write("No data found")
luci.http.write("\n")
end
-- route -n luci.http.write("\n")
local routeShow = ut.trim(sys.exec("route -n")) luci.http.write("\n")
if routeShow == "" then luci.http.write("Output of \"ip route list table 1-250\"")
routeShow = "No data found" luci.http.write("\n")
luci.http.write(dash)
luci.http.write("\n")
for i=1,250 do
local output = ut.trim(sys.exec(string.format("ip route list table %d", i)))
if output ~= "" then
luci.http.write(string.format("Table %s: ", i))
luci.http.write(output)
luci.http.write("\n")
end end
mArray.routeshow = { routeShow } end
-- ip rule show luci.http.write("\n")
local ipRuleShow = ut.trim(sys.exec(ip .. "rule show")) luci.http.write("\n")
if ipRuleShow == "" then local output = ut.trim(sys.exec("iptables -L -t mangle -v -n"))
ipRuleShow = "No data found" luci.http.write("Output of \"iptables -L -t mangle -v -n\"")
end luci.http.write("\n")
mArray.iprule = { ipRuleShow } luci.http.write(dash)
luci.http.write("\n")
-- ip route list table 1-250 if output ~= "" then
local routeList, routeString = ut.trim(sys.exec(ip .. "rule | sed 's/://g' 2>/dev/null | awk '$1>=2001 && $1<=2250' | awk '{print $NF}'")), "" luci.http.write(output)
if routeList ~= "" then luci.http.write("\n")
for line in routeList:gmatch("[^\r\n]+") do else
routeString = routeString .. line .. "\n" .. sys.exec(ip .. "route list table " .. line) luci.http.write("No data found")
end luci.http.write("\n")
routeString = ut.trim(routeString) end
else
routeString = "No data found"
end
mArray.routelist = { routeString }
-- default firewall output policy
local firewallOut = ut.trim(sys.exec("uci -q -p /var/state get firewall.@defaults[0].output"))
if firewallOut == "" then
firewallOut = "No data found"
end
mArray.firewallout = { firewallOut }
-- iptables
local iptables = ut.trim(sys.exec("iptables -L -t mangle -v -n"))
if iptables == "" then
iptables = "No data found"
end
mArray.iptables = { iptables }
luci.http.prepare_content("application/json")
luci.http.write_json(mArray)
end end

View file

@ -14,12 +14,14 @@ $Id$
local net = require "luci.model.network".init() local net = require "luci.model.network".init()
m = Map("mwan3")
s = m:section(NamedSection, "globals", "globals", translate("Globals mwan3 options")) m = Map("mwan3", translate("MWAN - Globals"))
s = m:section(NamedSection, "globals", "globals", nil)
n = s:option(ListValue, "local_source", n = s:option(ListValue, "local_source",
translate("Local source interface"), translate("Local source interface"),
translate("Use the IP address of this interface as source IP address for traffic initiated by the router itself")) translate("Use the IP address of this interface as source IP " ..
"address for traffic initiated by the router itself"))
n:value("none") n:value("none")
n.default = "none" n.default = "none"
for _, net in ipairs(net:get_networks()) do for _, net in ipairs(net:get_networks()) do

View file

@ -1,276 +1,208 @@
-- ------ extra functions ------ -- dsp = require "luci.dispatcher"
function interfaceCheck() -- find issues with too many interfaces, reliability and metric
uci.cursor():foreach("mwan3", "interface",
function (section)
local interfaceName = section[".name"]
interfaceNumber = interfaceNumber+1 -- count number of mwan interfaces configured
-- create list of metrics for none and duplicate checking
local metricValue = ut.trim(sys.exec("uci -p /var/state get network." .. interfaceName .. ".metric"))
if metricValue == "" then
errorFound = 1
errorNoMetricList = errorNoMetricList .. interfaceName .. " "
else
metricList = metricList .. interfaceName .. " " .. metricValue .. "\n"
end
-- check if any interfaces have a higher reliability requirement than tracking IPs configured
local trackingNumber = tonumber(ut.trim(sys.exec("echo $(uci -p /var/state get mwan3." .. interfaceName .. ".track_ip) | wc -w")))
if trackingNumber > 0 then
local reliabilityNumber = tonumber(ut.trim(sys.exec("uci -p /var/state get mwan3." .. interfaceName .. ".reliability")))
if reliabilityNumber and reliabilityNumber > trackingNumber then
errorFound = 1
errorReliabilityList = errorReliabilityList .. interfaceName .. " "
end
end
-- check if any interfaces are not properly configured in /etc/config/network or have no default route in main routing table
if ut.trim(sys.exec("uci -p /var/state get network." .. interfaceName)) == "interface" then
local interfaceDevice = ut.trim(sys.exec("uci -p /var/state get network." .. interfaceName .. ".ifname"))
if interfaceDevice == "uci: Entry not found" or interfaceDevice == "" then
errorFound = 1
errorNetConfigList = errorNetConfigList .. interfaceName .. " "
errorRouteList = errorRouteList .. interfaceName .. " "
else
local routeCheck = ut.trim(sys.exec("route -n | awk '{if ($8 == \"" .. interfaceDevice .. "\" && $1 == \"0.0.0.0\" && $3 == \"0.0.0.0\") print $1}'"))
if routeCheck == "" then
errorFound = 1
errorRouteList = errorRouteList .. interfaceName .. " "
end
end
else
errorFound = 1
errorNetConfigList = errorNetConfigList .. interfaceName .. " "
errorRouteList = errorRouteList .. interfaceName .. " "
end
end
)
-- check if any interfaces have duplicate metrics
local metricDuplicateNumbers = sys.exec("echo '" .. metricList .. "' | awk '{print $2}' | uniq -d")
if metricDuplicateNumbers ~= "" then
errorFound = 1
local metricDuplicates = ""
for line in metricDuplicateNumbers:gmatch("[^\r\n]+") do
metricDuplicates = sys.exec("echo '" .. metricList .. "' | grep '" .. line .. "' | awk '{print $1}'")
errorDuplicateMetricList = errorDuplicateMetricList .. metricDuplicates
end
errorDuplicateMetricList = sys.exec("echo '" .. errorDuplicateMetricList .. "' | tr '\n' ' '")
end
end
function interfaceWarnings() -- display status and warning messages at the top of the page function interfaceWarnings(overview, count)
local warnings = "" local warnings = ""
if interfaceNumber <= 250 then if count <= 250 then
warnings = "<strong>" .. translatef("There are currently %d of 250 supported interfaces configured", interfaceNumber) .. "</strong>" warnings = string.format("<strong>%s</strong></br>",
translatef("There are currently %d of 250 supported interfaces configured", count)
)
else else
warnings = "<font color=\"ff0000\"><strong>" .. translatef("WARNING: %d interfaces are configured exceeding the maximum of 250!", interfaceNumber) .. "</strong></font>" warnings = string.format("<strong>%s</strong></br>",
translatef("WARNING: %d interfaces are configured exceeding the maximum of 250!", count)
)
end end
if errorReliabilityList ~= " " then
warnings = warnings .. "<br /><br /><font color=\"ff0000\"><strong>" .. translate("WARNING: Some interfaces have a higher reliability requirement than there are tracking IP addresses!") .. "</strong></font>" for i, k in pairs(overview) do
end if overview[i]["network"] == false then
if errorRouteList ~= " " then warnings = warnings .. string.format("<strong>%s</strong></br>",
warnings = warnings .. "<br /><br /><font color=\"ff0000\"><strong>" .. translate("WARNING: Some interfaces have no default route in the main routing table!") .. "</strong></font>" translatef("WARNING: Interface %s are not found in /etc/config/network", i)
end )
if errorNetConfigList ~= " " then end
warnings = warnings .. "<br /><br /><font color=\"ff0000\"><strong>" .. translate("WARNING: Some interfaces are configured incorrectly or not at all in /etc/config/network!") .. "</strong></font>"
end if overview[i]["default_route"] == false then
if errorNoMetricList ~= " " then warnings = warnings .. string.format("<strong>%s</strong></br>",
warnings = warnings .. "<br /><br /><font color=\"ff0000\"><strong>" .. translate("WARNING: Some interfaces have no metric configured in /etc/config/network!") .. "</strong></font>" translatef("WARNING: Interface %s has no default route in the main routing table", i)
end )
if errorDuplicateMetricList ~= " " then end
warnings = warnings .. "<br /><br /><font color=\"ff0000\"><strong>" .. translate("WARNING: Some interfaces have duplicate metrics configured in /etc/config/network!") .. "</strong></font>"
if overview[i]["reliability"] == false then
warnings = warnings .. string.format("<strong>%s</strong></br>",
translatef("WARNING: Interface %s has a higher reliability " ..
"requirement than tracking hosts (%d)", i, overview[i]["tracking"])
)
end
if overview[i]["duplicate_metric"] == true then
warnings = warnings .. string.format("<strong>%s</strong></br>",
translatef("WARNING: Interface %s has a duplicate metric %s configured", i, overview[i]["metric"])
)
end
end end
return warnings return warnings
end end
-- ------ interface configuration ------ -- function configCheck()
local overview = {}
local count = 0
local duplicate_metric = {}
uci.cursor():foreach("mwan3", "interface",
function (section)
local uci = uci.cursor(nil, "/var/state")
local iface = section[".name"]
overview[iface] = {}
count = count + 1
local network = uci:get("network", iface)
overview[iface]["network"] = false
if network ~= nil then
overview[iface]["network"] = true
dsp = require "luci.dispatcher" local device = uci:get("network", iface, "ifname")
sys = require "luci.sys" if device ~= nil then
ut = require "luci.util" overview[iface]["device"] = device
end
interfaceNumber = 0 local metric = uci:get("network", iface, "metric")
metricList = "" if metric ~= nil then
errorFound = 0 overview[iface]["metric"] = metric
errorDuplicateMetricList = " " overview[iface]["duplicate_metric"] = false
errorNetConfigList = " " for _, m in ipairs(duplicate_metric) do
errorNoMetricList = " " if m == metric then
errorReliabilityList = " " overview[iface]["duplicate_metric"] = true
errorRouteList = " " end
interfaceCheck() end
table.insert(duplicate_metric, metric)
end
local dump = require("luci.util").ubus("network.interface.%s" % iface, "status", {})
overview[iface]["default_route"] = false
if dump then
local _, route
for _, route in ipairs(dump.route) do
if dump.route[_].target == "0.0.0.0" then
overview[iface]["default_route"] = true
end
end
end
end
m5 = Map("mwan3", translate("MWAN Interface Configuration"), local trackingNumber = uci:get("mwan3", iface, "track_ip")
interfaceWarnings()) overview[iface]["tracking"] = 0
m5:append(Template("mwan/config_css")) if #trackingNumber > 0 then
overview[iface]["tracking"] = #trackingNumber
overview[iface]["reliability"] = false
local reliabilityNumber = tonumber(uci:get("mwan3", iface, "reliability"))
if reliabilityNumber and reliabilityNumber <= #trackingNumber then
overview[iface]["reliability"] = true
end
end
end
)
return overview, count
end
m5 = Map("mwan3", translate("MWAN - Interfaces"),
interfaceWarnings(configCheck()))
mwan_interface = m5:section(TypedSection, "interface", translate("Interfaces"), mwan_interface = m5:section(TypedSection, "interface", nil,
translate("MWAN supports up to 250 physical and/or logical interfaces<br />" .. translate("MWAN supports up to 250 physical and/or logical interfaces<br />" ..
"MWAN requires that all interfaces have a unique metric configured in /etc/config/network<br />" .. "MWAN requires that all interfaces have a unique metric configured in /etc/config/network<br />" ..
"Names must match the interface name found in /etc/config/network (see advanced tab)<br />" .. "Names must match the interface name found in /etc/config/network (see advanced tab)<br />" ..
"Names may contain characters A-Z, a-z, 0-9, _ and no spaces<br />" .. "Names may contain characters A-Z, a-z, 0-9, _ and no spaces<br />" ..
"Interfaces may not share the same name as configured members, policies or rules")) "Interfaces may not share the same name as configured members, policies or rules"))
mwan_interface.addremove = true mwan_interface.addremove = true
mwan_interface.dynamic = false mwan_interface.dynamic = false
mwan_interface.sectionhead = translate("Interface") mwan_interface.sectionhead = translate("Interface")
mwan_interface.sortable = false mwan_interface.sortable = false
mwan_interface.template = "cbi/tblsection" mwan_interface.template = "cbi/tblsection"
mwan_interface.extedit = dsp.build_url("admin", "network", "mwan", "interface", "%s") mwan_interface.extedit = dsp.build_url("admin", "network", "mwan", "interface", "%s")
function mwan_interface.create(self, section) function mwan_interface.create(self, section)
TypedSection.create(self, section) TypedSection.create(self, section)
m5.uci:save("mwan3") m5.uci:save("mwan3")
luci.http.redirect(dsp.build_url("admin", "network", "mwan", "interface", section)) luci.http.redirect(dsp.build_url("admin", "network", "mwan", "interface", section))
end end
enabled = mwan_interface:option(DummyValue, "enabled", translate("Enabled")) enabled = mwan_interface:option(DummyValue, "enabled", translate("Enabled"))
enabled.rawhtml = true enabled.rawhtml = true
function enabled.cfgvalue(self, s) function enabled.cfgvalue(self, s)
if self.map:get(s, "enabled") == "1" then if self.map:get(s, "enabled") == "1" then
return "Yes" return translate("Yes")
else else
return "No" return translate("No")
end
end
track_ip = mwan_interface:option(DummyValue, "track_ip", translate("Tracking IP"))
track_ip.rawhtml = true
function track_ip.cfgvalue(self, s)
tracked = self.map:get(s, "track_ip")
if tracked then
local ipList = ""
for k,v in pairs(tracked) do
ipList = ipList .. v .. "<br />"
end
return ipList
else
return "&#8212;"
end
end end
end
track_method = mwan_interface:option(DummyValue, "track_method", translate("Tracking method")) track_method = mwan_interface:option(DummyValue, "track_method", translate("Tracking method"))
track_method.rawhtml = true track_method.rawhtml = true
function track_method.cfgvalue(self, s) function track_method.cfgvalue(self, s)
if tracked then local tracked = self.map:get(s, "track_ip")
return self.map:get(s, "track_method") or "&#8212;" if tracked then
else return self.map:get(s, "track_method") or "&#8212;"
return "&#8212;" else
end return "&#8212;"
end end
end
reliability = mwan_interface:option(DummyValue, "reliability", translate("Tracking reliability")) reliability = mwan_interface:option(DummyValue, "reliability", translate("Tracking reliability"))
reliability.rawhtml = true reliability.rawhtml = true
function reliability.cfgvalue(self, s) function reliability.cfgvalue(self, s)
if tracked then local tracked = self.map:get(s, "track_ip")
return self.map:get(s, "reliability") or "&#8212;" if tracked then
else return self.map:get(s, "reliability") or "&#8212;"
return "&#8212;" else
end return "&#8212;"
end
count = mwan_interface:option(DummyValue, "count", translate("Ping count"))
count.rawhtml = true
function count.cfgvalue(self, s)
if tracked then
return self.map:get(s, "count") or "&#8212;"
else
return "&#8212;"
end
end
timeout = mwan_interface:option(DummyValue, "timeout", translate("Ping timeout"))
timeout.rawhtml = true
function timeout.cfgvalue(self, s)
if tracked then
local timeoutValue = self.map:get(s, "timeout")
if timeoutValue then
return timeoutValue .. "s"
else
return "&#8212;"
end
else
return "&#8212;"
end
end end
end
interval = mwan_interface:option(DummyValue, "interval", translate("Ping interval")) interval = mwan_interface:option(DummyValue, "interval", translate("Ping interval"))
interval.rawhtml = true interval.rawhtml = true
function interval.cfgvalue(self, s) function interval.cfgvalue(self, s)
if tracked then local tracked = self.map:get(s, "track_ip")
local intervalValue = self.map:get(s, "interval") if tracked then
if intervalValue then local intervalValue = self.map:get(s, "interval")
return intervalValue .. "s" if intervalValue then
else return intervalValue .. "s"
return "&#8212;"
end
else else
return "&#8212;" return "&#8212;"
end end
else
return "&#8212;"
end end
end
down = mwan_interface:option(DummyValue, "down", translate("Interface down")) down = mwan_interface:option(DummyValue, "down", translate("Interface down"))
down.rawhtml = true down.rawhtml = true
function down.cfgvalue(self, s) function down.cfgvalue(self, s)
if tracked then local tracked = self.map:get(s, "track_ip")
return self.map:get(s, "down") or "&#8212;" if tracked then
else return self.map:get(s, "down") or "&#8212;"
return "&#8212;" else
end return "&#8212;"
end end
end
up = mwan_interface:option(DummyValue, "up", translate("Interface up")) up = mwan_interface:option(DummyValue, "up", translate("Interface up"))
up.rawhtml = true up.rawhtml = true
function up.cfgvalue(self, s) function up.cfgvalue(self, s)
if tracked then local tracked = self.map:get(s, "track_ip")
return self.map:get(s, "up") or "&#8212;" if tracked then
else return self.map:get(s, "up") or "&#8212;"
return "&#8212;" else
end return "&#8212;"
end end
end
metric = mwan_interface:option(DummyValue, "metric", translate("Metric")) metric = mwan_interface:option(DummyValue, "metric", translate("Metric"))
metric.rawhtml = true metric.rawhtml = true
function metric.cfgvalue(self, s) function metric.cfgvalue(self, s)
local metricValue = sys.exec("uci -p /var/state get network." .. s .. ".metric") local uci = uci.cursor(nil, "/var/state")
if metricValue ~= "" then local metric = uci:get("network", s, "metric")
return metricValue if metric then
else return metric
return "&#8212;" else
end return "&#8212;"
end end
end
errors = mwan_interface:option(DummyValue, "errors", translate("Errors"))
errors.rawhtml = true
function errors.cfgvalue(self, s)
if errorFound == 1 then
local mouseOver, lineBreak = "", ""
if string.find(errorReliabilityList, " " .. s .. " ") then
mouseOver = "Higher reliability requirement than there are tracking IP addresses"
lineBreak = "&#10;&#10;"
end
if string.find(errorRouteList, " " .. s .. " ") then
mouseOver = mouseOver .. lineBreak .. "No default route in the main routing table"
lineBreak = "&#10;&#10;"
end
if string.find(errorNetConfigList, " " .. s .. " ") then
mouseOver = mouseOver .. lineBreak .. "Configured incorrectly or not at all in /etc/config/network"
lineBreak = "&#10;&#10;"
end
if string.find(errorNoMetricList, " " .. s .. " ") then
mouseOver = mouseOver .. lineBreak .. "No metric configured in /etc/config/network"
lineBreak = "&#10;&#10;"
end
if string.find(errorDuplicateMetricList, " " .. s .. " ") then
mouseOver = mouseOver .. lineBreak .. "Duplicate metric configured in /etc/config/network"
end
if mouseOver == "" then
return ""
else
return "<span title=\"" .. mouseOver .. "\"><img src=\"/luci-static/resources/cbi/reset.gif\" alt=\"error\"></img></span>"
end
else
return ""
end
end
return m5 return m5

View file

@ -1,266 +1,179 @@
-- ------ extra functions ------ --
function interfaceCheck()
metricValue = ut.trim(sys.exec("uci -p /var/state get network." .. arg[1] .. ".metric"))
if metricValue == "" then -- no metric
errorNoMetric = 1
else -- if metric exists create list of interface metrics to compare against for duplicates
uci.cursor():foreach("mwan3", "interface",
function (section)
local metricValue = ut.trim(sys.exec("uci -p /var/state get network." .. section[".name"] .. ".metric"))
metricList = metricList .. section[".name"] .. " " .. metricValue .. "\n"
end
)
-- compare metric against list
local metricDuplicateNumbers, metricDuplicates = sys.exec("echo '" .. metricList .. "' | awk '{print $2}' | uniq -d"), ""
for line in metricDuplicateNumbers:gmatch("[^\r\n]+") do
metricDuplicates = sys.exec("echo '" .. metricList .. "' | grep '" .. line .. "' | awk '{print $1}'")
errorDuplicateMetricList = errorDuplicateMetricList .. metricDuplicates
end
if sys.exec("echo '" .. errorDuplicateMetricList .. "' | grep -w " .. arg[1]) ~= "" then
errorDuplicateMetric = 1
end
end
-- check if this interface has a higher reliability requirement than track IPs configured
local trackingNumber = tonumber(ut.trim(sys.exec("echo $(uci -p /var/state get mwan3." .. arg[1] .. ".track_ip) | wc -w")))
if trackingNumber > 0 then
local reliabilityNumber = tonumber(ut.trim(sys.exec("uci -p /var/state get mwan3." .. arg[1] .. ".reliability")))
if reliabilityNumber and reliabilityNumber > trackingNumber then
errorReliability = 1
end
end
-- check if any interfaces are not properly configured in /etc/config/network or have no default route in main routing table
if ut.trim(sys.exec("uci -p /var/state get network." .. arg[1])) == "interface" then
local interfaceDevice = ut.trim(sys.exec("uci -p /var/state get network." .. arg[1] .. ".ifname"))
if interfaceDevice == "uci: Entry not found" or interfaceDevice == "" then
errorNetConfig = 1
errorRoute = 1
else
local routeCheck = ut.trim(sys.exec("route -n | awk '{if ($8 == \"" .. interfaceDevice .. "\" && $1 == \"0.0.0.0\" && $3 == \"0.0.0.0\") print $1}'"))
if routeCheck == "" then
errorRoute = 1
end
end
else
errorNetConfig = 1
errorRoute = 1
end
end
function interfaceWarnings() -- display warning messages at the top of the page
local warns, lineBreak = "", ""
if errorReliability == 1 then
warns = "<font color=\"ff0000\"><strong>" .. translate("WARNING: This interface has a higher reliability requirement than there are tracking IP addresses!") .. "</strong></font>"
lineBreak = "<br /><br />"
end
if errorRoute == 1 then
warns = warns .. lineBreak .. "<font color=\"ff0000\"><strong>" .. translate("WARNING: This interface has no default route in the main routing table!") .. "</strong></font>"
lineBreak = "<br /><br />"
end
if errorNetConfig == 1 then
warns = warns .. lineBreak .. "<font color=\"ff0000\"><strong>" .. translate("WARNING: This interface is configured incorrectly or not at all in /etc/config/network!") .. "</strong></font>"
lineBreak = "<br /><br />"
end
if errorNoMetric == 1 then
warns = warns .. lineBreak .. "<font color=\"ff0000\"><strong>" .. translate("WARNING: This interface has no metric configured in /etc/config/network!") .. "</strong></font>"
elseif errorDuplicateMetric == 1 then
warns = warns .. lineBreak .. "<font color=\"ff0000\"><strong>" .. translate("WARNING: This and other interfaces have duplicate metrics configured in /etc/config/network!") .. "</strong></font>"
end
return warns
end
-- ------ interface configuration ------ --
dsp = require "luci.dispatcher" dsp = require "luci.dispatcher"
sys = require "luci.sys"
ut = require "luci.util"
arg[1] = arg[1] or "" arg[1] = arg[1] or ""
metricValue = ""
metricList = ""
errorDuplicateMetricList = ""
errorNoMetric = 0
errorDuplicateMetric = 0
errorRoute = 0
errorNetConfig = 0
errorReliability = 0
interfaceCheck()
m5 = Map("mwan3", translatef("MWAN Interface Configuration - %s", arg[1]))
m5 = Map("mwan3", translatef("MWAN Interface Configuration - %s", arg[1]),
interfaceWarnings())
m5.redirect = dsp.build_url("admin", "network", "mwan", "interface") m5.redirect = dsp.build_url("admin", "network", "mwan", "interface")
mwan_interface = m5:section(NamedSection, arg[1], "interface", "") mwan_interface = m5:section(NamedSection, arg[1], "interface", "")
mwan_interface.addremove = false mwan_interface.addremove = false
mwan_interface.dynamic = false mwan_interface.dynamic = false
enabled = mwan_interface:option(ListValue, "enabled", translate("Enabled")) enabled = mwan_interface:option(ListValue, "enabled", translate("Enabled"))
enabled.default = "1" enabled.default = "1"
enabled:value("1", translate("Yes")) enabled:value("1", translate("Yes"))
enabled:value("0", translate("No")) enabled:value("0", translate("No"))
initial_state = mwan_interface:option(ListValue, "initial_state", translate("Initial state"), initial_state = mwan_interface:option(ListValue, "initial_state", translate("Initial state"),
translate("Expect interface state on up event")) translate("Expect interface state on up event"))
initial_state.default = "online" initial_state.default = "online"
initial_state:value("online", translate("Online")) initial_state:value("online", translate("Online"))
initial_state:value("offline", translate("Offline")) initial_state:value("offline", translate("Offline"))
family = mwan_interface:option(ListValue, "family", translate("Internet Protocol")) family = mwan_interface:option(ListValue, "family", translate("Internet Protocol"))
family.default = "ipv4" family.default = "ipv4"
family:value("ipv4", translate("IPv4")) family:value("ipv4", translate("IPv4"))
family:value("ipv6", translate("IPv6")) family:value("ipv6", translate("IPv6"))
track_ip = mwan_interface:option(DynamicList, "track_ip", translate("Tracking hostname or IP address"), track_ip = mwan_interface:option(DynamicList, "track_ip", translate("Tracking hostname or IP address"),
translate("This hostname or IP address will be pinged to determine if the link is up or down. Leave blank to assume interface is always online")) translate("This hostname or IP address will be pinged to determine if the link is up or down. Leave blank to assume interface is always online"))
track_ip.datatype = "host" track_ip.datatype = "host"
track_method = mwan_interface:option(ListValue, "track_method", translate("Tracking method")) track_method = mwan_interface:option(ListValue, "track_method", translate("Tracking method"))
track_method.default = "ping" track_method.default = "ping"
track_method:value("ping") track_method:value("ping")
track_method:value("arping") track_method:value("arping")
track_method:value("httping") track_method:value("httping")
reliability = mwan_interface:option(Value, "reliability", translate("Tracking reliability"), reliability = mwan_interface:option(Value, "reliability", translate("Tracking reliability"),
translate("Acceptable values: 1-100. This many Tracking IP addresses must respond for the link to be deemed up")) translate("Acceptable values: 1-100. This many Tracking IP addresses must respond for the link to be deemed up"))
reliability.datatype = "range(1, 100)" reliability.datatype = "range(1, 100)"
reliability.default = "1" reliability.default = "1"
count = mwan_interface:option(ListValue, "count", translate("Ping count")) count = mwan_interface:option(ListValue, "count", translate("Ping count"))
count.default = "1" count.default = "1"
count:value("1") count:value("1")
count:value("2") count:value("2")
count:value("3") count:value("3")
count:value("4") count:value("4")
count:value("5") count:value("5")
size = mwan_interface:option(Value, "size", translate("Ping size")) size = mwan_interface:option(Value, "size", translate("Ping size"))
size.default = "56" size.default = "56"
size:value("8") size:value("8")
size:value("24") size:value("24")
size:value("56") size:value("56")
size:value("120") size:value("120")
size:value("248") size:value("248")
size:value("504") size:value("504")
size:value("1016") size:value("1016")
size:value("1472") size:value("1472")
size:value("2040") size:value("2040")
size.datatype = "range(1, 65507)" size.datatype = "range(1, 65507)"
size.rmempty = false size.rmempty = false
size.optional = false size.optional = false
timeout = mwan_interface:option(ListValue, "timeout", translate("Ping timeout")) timeout = mwan_interface:option(ListValue, "timeout", translate("Ping timeout"))
timeout.default = "2" timeout.default = "2"
timeout:value("1", translatef("%d second", 1)) timeout:value("1", translatef("%d second", 1))
timeout:value("2", translatef("%d seconds", 2)) timeout:value("2", translatef("%d seconds", 2))
timeout:value("3", translatef("%d seconds", 3)) timeout:value("3", translatef("%d seconds", 3))
timeout:value("4", translatef("%d seconds", 4)) timeout:value("4", translatef("%d seconds", 4))
timeout:value("5", translatef("%d seconds", 5)) timeout:value("5", translatef("%d seconds", 5))
timeout:value("6", translatef("%d seconds", 6)) timeout:value("6", translatef("%d seconds", 6))
timeout:value("7", translatef("%d seconds", 7)) timeout:value("7", translatef("%d seconds", 7))
timeout:value("8", translatef("%d seconds", 8)) timeout:value("8", translatef("%d seconds", 8))
timeout:value("9", translatef("%d seconds", 9)) timeout:value("9", translatef("%d seconds", 9))
timeout:value("10", translatef("%d seconds", 10)) timeout:value("10", translatef("%d seconds", 10))
interval = mwan_interface:option(ListValue, "interval", translate("Ping interval")) interval = mwan_interface:option(ListValue, "interval", translate("Ping interval"))
interval.default = "5" interval.default = "5"
interval:value("1", translatef("%d second", 1)) interval:value("1", translatef("%d second", 1))
interval:value("3", translatef("%d seconds", 3)) interval:value("3", translatef("%d seconds", 3))
interval:value("5", translatef("%d seconds", 5)) interval:value("5", translatef("%d seconds", 5))
interval:value("10", translatef("%d seconds", 10)) interval:value("10", translatef("%d seconds", 10))
interval:value("20", translatef("%d seconds", 20)) interval:value("20", translatef("%d seconds", 20))
interval:value("30", translatef("%d seconds", 30)) interval:value("30", translatef("%d seconds", 30))
interval:value("60", translatef("%d minute", 1)) interval:value("60", translatef("%d minute", 1))
interval:value("300", translatef("%d minutes", 5)) interval:value("300", translatef("%d minutes", 5))
interval:value("600", translatef("%d minutes", 10)) interval:value("600", translatef("%d minutes", 10))
interval:value("900", translatef("%d minutes", 15)) interval:value("900", translatef("%d minutes", 15))
interval:value("1800", translatef("%d minutes", 30)) interval:value("1800", translatef("%d minutes", 30))
interval:value("3600", translatef("%d hour", 1)) interval:value("3600", translatef("%d hour", 1))
failure = mwan_interface:option(Value, "failure_interval", translate("Failure interval"), failure = mwan_interface:option(Value, "failure_interval", translate("Failure interval"),
translate("Ping interval during failure detection")) translate("Ping interval during failure detection"))
failure.default = "5" failure.default = "5"
failure:value("1", translatef("%d second", 1)) failure:value("1", translatef("%d second", 1))
failure:value("3", translatef("%d seconds", 3)) failure:value("3", translatef("%d seconds", 3))
failure:value("5", translatef("%d seconds", 5)) failure:value("5", translatef("%d seconds", 5))
failure:value("10", translatef("%d seconds", 10)) failure:value("10", translatef("%d seconds", 10))
failure:value("20", translatef("%d seconds", 20)) failure:value("20", translatef("%d seconds", 20))
failure:value("30", translatef("%d seconds", 30)) failure:value("30", translatef("%d seconds", 30))
failure:value("60", translatef("%d minute", 1)) failure:value("60", translatef("%d minute", 1))
failure:value("300", translatef("%d minutes", 5)) failure:value("300", translatef("%d minutes", 5))
failure:value("600", translatef("%d minutes", 10)) failure:value("600", translatef("%d minutes", 10))
failure:value("900", translatef("%d minutes", 15)) failure:value("900", translatef("%d minutes", 15))
failure:value("1800", translatef("%d minutes", 30)) failure:value("1800", translatef("%d minutes", 30))
failure:value("3600", translatef("%d hour", 1)) failure:value("3600", translatef("%d hour", 1))
keep_failure = mwan_interface:option(Flag, "keep_failure_interval", translate("Keep failure interval"), keep_failure = mwan_interface:option(Flag, "keep_failure_interval", translate("Keep failure interval"),
translate("Keep ping failure interval during failure state")) translate("Keep ping failure interval during failure state"))
keep_failure.default = keep_failure.disabled keep_failure.default = keep_failure.disabled
recovery = mwan_interface:option(Value, "recovery_interval", translate("Recovery interval"), recovery = mwan_interface:option(Value, "recovery_interval", translate("Recovery interval"),
translate("Ping interval during failure recovering")) translate("Ping interval during failure recovering"))
recovery.default = "5" recovery.default = "5"
recovery:value("1", translatef("%d second", 1)) recovery:value("1", translatef("%d second", 1))
recovery:value("3", translatef("%d seconds", 3)) recovery:value("3", translatef("%d seconds", 3))
recovery:value("5", translatef("%d seconds", 5)) recovery:value("5", translatef("%d seconds", 5))
recovery:value("10", translatef("%d seconds", 10)) recovery:value("10", translatef("%d seconds", 10))
recovery:value("20", translatef("%d seconds", 20)) recovery:value("20", translatef("%d seconds", 20))
recovery:value("30", translatef("%d seconds", 30)) recovery:value("30", translatef("%d seconds", 30))
recovery:value("60", translatef("%d minute", 1)) recovery:value("60", translatef("%d minute", 1))
recovery:value("300", translatef("%d minutes", 5)) recovery:value("300", translatef("%d minutes", 5))
recovery:value("600", translatef("%d minutes", 10)) recovery:value("600", translatef("%d minutes", 10))
recovery:value("900", translatef("%d minutes", 15)) recovery:value("900", translatef("%d minutes", 15))
recovery:value("1800", translatef("%d minutes", 30)) recovery:value("1800", translatef("%d minutes", 30))
recovery:value("3600", translatef("%d hour", 1)) recovery:value("3600", translatef("%d hour", 1))
down = mwan_interface:option(ListValue, "down", translate("Interface down"), down = mwan_interface:option(ListValue, "down", translate("Interface down"),
translate("Interface will be deemed down after this many failed ping tests")) translate("Interface will be deemed down after this many failed ping tests"))
down.default = "3" down.default = "3"
down:value("1") down:value("1")
down:value("2") down:value("2")
down:value("3") down:value("3")
down:value("4") down:value("4")
down:value("5") down:value("5")
down:value("6") down:value("6")
down:value("7") down:value("7")
down:value("8") down:value("8")
down:value("9") down:value("9")
down:value("10") down:value("10")
up = mwan_interface:option(ListValue, "up", translate("Interface up"), up = mwan_interface:option(ListValue, "up", translate("Interface up"),
translate("Downed interface will be deemed up after this many successful ping tests")) translate("Downed interface will be deemed up after this many successful ping tests"))
up.default = "3" up.default = "3"
up:value("1") up:value("1")
up:value("2") up:value("2")
up:value("3") up:value("3")
up:value("4") up:value("4")
up:value("5") up:value("5")
up:value("6") up:value("6")
up:value("7") up:value("7")
up:value("8") up:value("8")
up:value("9") up:value("9")
up:value("10") up:value("10")
flush = mwan_interface:option(ListValue, "flush_conntrack", translate("Flush conntrack table"), flush = mwan_interface:option(ListValue, "flush_conntrack", translate("Flush conntrack table"),
translate("Flush global firewall conntrack table on interface events")) translate("Flush global firewall conntrack table on interface events"))
flush.default = "never" flush.default = "never"
flush:value("ifup", translate("ifup")) flush:value("ifup", translate("ifup"))
flush:value("ifdown", translate("ifdown")) flush:value("ifdown", translate("ifdown"))
flush:value("never", translate("never")) flush:value("never", translate("never"))
flush:value("always", translate("always")) flush:value("always", translate("always"))
metric = mwan_interface:option(DummyValue, "metric", translate("Metric"), metric = mwan_interface:option(DummyValue, "metric", translate("Metric"),
translate("This displays the metric assigned to this interface in /etc/config/network")) translate("This displays the metric assigned to this interface in /etc/config/network"))
metric.rawhtml = true metric.rawhtml = true
function metric.cfgvalue(self, s) function metric.cfgvalue(self, s)
if errorNoMetric == 0 then local uci = uci.cursor(nil, "/var/state")
return metricValue local metric = uci:get("network", arg[1], "metric")
else if metric then
return "&#8212;" return metric
end else
return "&#8212;"
end end
end
return m5 return m5

View file

@ -1,46 +1,40 @@
-- ------ member configuration ------ -- dsp = require "luci.dispatcher"
ds = require "luci.dispatcher"
m5 = Map("mwan3", translate("MWAN Member Configuration")) m5 = Map("mwan3", translate("MWAN - Members"))
m5:append(Template("mwan/config_css"))
mwan_member = m5:section(TypedSection, "member", nil,
mwan_member = m5:section(TypedSection, "member", translate("Members"),
translate("Members are profiles attaching a metric and weight to an MWAN interface<br />" .. translate("Members are profiles attaching a metric and weight to an MWAN interface<br />" ..
"Names may contain characters A-Z, a-z, 0-9, _ and no spaces<br />" .. "Names may contain characters A-Z, a-z, 0-9, _ and no spaces<br />" ..
"Members may not share the same name as configured interfaces, policies or rules")) "Members may not share the same name as configured interfaces, policies or rules"))
mwan_member.addremove = true mwan_member.addremove = true
mwan_member.dynamic = false mwan_member.dynamic = false
mwan_member.sectionhead = translate("Member") mwan_member.sectionhead = translate("Member")
mwan_member.sortable = true mwan_member.sortable = true
mwan_member.template = "cbi/tblsection" mwan_member.template = "cbi/tblsection"
mwan_member.extedit = ds.build_url("admin", "network", "mwan", "member", "%s") mwan_member.extedit = dsp.build_url("admin", "network", "mwan", "member", "%s")
function mwan_member.create(self, section) function mwan_member.create(self, section)
TypedSection.create(self, section) TypedSection.create(self, section)
m5.uci:save("mwan3") m5.uci:save("mwan3")
luci.http.redirect(ds.build_url("admin", "network", "mwan", "member", section)) luci.http.redirect(dsp.build_url("admin", "network", "mwan", "member", section))
end end
interface = mwan_member:option(DummyValue, "interface", translate("Interface")) interface = mwan_member:option(DummyValue, "interface", translate("Interface"))
interface.rawhtml = true interface.rawhtml = true
function interface.cfgvalue(self, s) function interface.cfgvalue(self, s)
return self.map:get(s, "interface") or "&#8212;" return self.map:get(s, "interface") or "&#8212;"
end end
metric = mwan_member:option(DummyValue, "metric", translate("Metric")) metric = mwan_member:option(DummyValue, "metric", translate("Metric"))
metric.rawhtml = true metric.rawhtml = true
function metric.cfgvalue(self, s) function metric.cfgvalue(self, s)
return self.map:get(s, "metric") or "1" return self.map:get(s, "metric") or "1"
end end
weight = mwan_member:option(DummyValue, "weight", translate("Weight")) weight = mwan_member:option(DummyValue, "weight", translate("Weight"))
weight.rawhtml = true weight.rawhtml = true
function weight.cfgvalue(self, s) function weight.cfgvalue(self, s)
return self.map:get(s, "weight") or "1" return self.map:get(s, "weight") or "1"
end end
return m5 return m5

View file

@ -1,47 +1,27 @@
-- ------ extra functions ------ --
function cbi_add_interface(field)
uci.cursor():foreach("mwan3", "interface",
function (section)
field:value(section[".name"])
end
)
end
-- ------ member configuration ------ --
dsp = require "luci.dispatcher" dsp = require "luci.dispatcher"
arg[1] = arg[1] or "" arg[1] = arg[1] or ""
m5 = Map("mwan3", translatef("MWAN Member Configuration - %s", arg[1])) m5 = Map("mwan3", translatef("MWAN Member Configuration - %s", arg[1]))
m5.redirect = dsp.build_url("admin", "network", "mwan", "member") m5.redirect = dsp.build_url("admin", "network", "mwan", "member")
mwan_member = m5:section(NamedSection, arg[1], "member", "") mwan_member = m5:section(NamedSection, arg[1], "member", "")
mwan_member.addremove = false mwan_member.addremove = false
mwan_member.dynamic = false mwan_member.dynamic = false
interface = mwan_member:option(Value, "interface", translate("Interface")) interface = mwan_member:option(Value, "interface", translate("Interface"))
cbi_add_interface(interface) m5.uci:foreach("mwan3", "interface",
function(s)
interface:value(s['.name'], s['.name'])
end
)
metric = mwan_member:option(Value, "metric", translate("Metric"), metric = mwan_member:option(Value, "metric", translate("Metric"),
translate("Acceptable values: 1-256. Defaults to 1 if not set")) translate("Acceptable values: 1-256. Defaults to 1 if not set"))
metric.datatype = "range(1, 256)" metric.datatype = "range(1, 256)"
weight = mwan_member:option(Value, "weight", translate("Weight"), weight = mwan_member:option(Value, "weight", translate("Weight"),
translate("Acceptable values: 1-1000. Defaults to 1 if not set")) translate("Acceptable values: 1-1000. Defaults to 1 if not set"))
weight.datatype = "range(1, 1000)" weight.datatype = "range(1, 1000)"
-- ------ currently configured interfaces ------ --
mwan_interface = m5:section(TypedSection, "interface", translate("Currently Configured Interfaces"))
mwan_interface.addremove = false
mwan_interface.dynamic = false
mwan_interface.sortable = false
mwan_interface.template = "cbi/tblsection"
return m5 return m5

View file

@ -1,12 +1,11 @@
-- ------ hotplug script configuration ------ --
local fs = require "nixio.fs" local fs = require "nixio.fs"
local ut = require "luci.util" local ut = require "luci.util"
script = "/etc/mwan3.user" script = "/etc/mwan3.user"
m5 = SimpleForm("luci", nil)
f = m5:section(SimpleSection, translate("MWAN Notification"), m5 = SimpleForm("luci", translate("MWAN - Notification"))
f = m5:section(SimpleSection, nil,
translate("This section allows you to modify the content of \"/etc/mwan3.user\".<br />" .. translate("This section allows you to modify the content of \"/etc/mwan3.user\".<br />" ..
"The file is also preserved during sysupgrade.<br />" .. "The file is also preserved during sysupgrade.<br />" ..
"<br />" .. "<br />" ..

View file

@ -1,94 +1,80 @@
-- ------ extra functions ------ -- dsp = require "luci.dispatcher"
function policyCheck()
local policy_error = {}
function policyCheck() -- check to see if any policy names exceed the maximum of 15 characters
uci.cursor():foreach("mwan3", "policy", uci.cursor():foreach("mwan3", "policy",
function (section) function (section)
policy_error[section[".name"]] = false
if string.len(section[".name"]) > 15 then if string.len(section[".name"]) > 15 then
nameTooLong = 1 policy_error[section[".name"]] = true
err_name_list = err_name_list .. section[".name"] .. " "
end end
end end
) )
return policy_error
end end
function policyWarn() -- display status and warning messages at the top of the page function policyError(policy_error)
if nameTooLong == 1 then local warnings = ""
return "<font color=\"ff0000\"><strong>" .. translate("WARNING: Some policies have names exceeding the maximum of 15 characters!") .. "</strong></font>" for i, k in pairs(policy_error) do
else if policy_error[i] == true then
return "" warnings = warnings .. string.format("<strong>%s</strong></br>",
translatef("WARNING: Policie %s has exceeding the maximum name of 15 characters", i)
)
end
end end
return warnings
end end
-- ------ policy configuration ------ -- m5 = Map("mwan3", translate("MWAN - Policies"),
policyError(policyCheck()))
ds = require "luci.dispatcher" mwan_policy = m5:section(TypedSection, "policy", nil,
sys = require "luci.sys"
nameTooLong = 0
err_name_list = " "
policyCheck()
m5 = Map("mwan3", translate("MWAN Policy Configuration"),
policyWarn())
m5:append(Template("mwan/config_css"))
mwan_policy = m5:section(TypedSection, "policy", translate("Policies"),
translate("Policies are profiles grouping one or more members controlling how MWAN distributes traffic<br />" .. translate("Policies are profiles grouping one or more members controlling how MWAN distributes traffic<br />" ..
"Member interfaces with lower metrics are used first. Interfaces with the same metric load-balance<br />" .. "Member interfaces with lower metrics are used first. Interfaces with the same metric load-balance<br />" ..
"Load-balanced member interfaces distribute more traffic out those with higher weights<br />" .. "Load-balanced member interfaces distribute more traffic out those with higher weights<br />" ..
"Names may contain characters A-Z, a-z, 0-9, _ and no spaces. Names must be 15 characters or less<br />" .. "Names may contain characters A-Z, a-z, 0-9, _ and no spaces. Names must be 15 characters or less<br />" ..
"Policies may not share the same name as configured interfaces, members or rules")) "Policies may not share the same name as configured interfaces, members or rules"))
mwan_policy.addremove = true mwan_policy.addremove = true
mwan_policy.dynamic = false mwan_policy.dynamic = false
mwan_policy.sectionhead = translate("Policy") mwan_policy.sectionhead = translate("Policy")
mwan_policy.sortable = true mwan_policy.sortable = true
mwan_policy.template = "cbi/tblsection" mwan_policy.template = "cbi/tblsection"
mwan_policy.extedit = ds.build_url("admin", "network", "mwan", "policy", "%s") mwan_policy.extedit = dsp.build_url("admin", "network", "mwan", "policy", "%s")
function mwan_policy.create(self, section) function mwan_policy.create(self, section)
TypedSection.create(self, section) TypedSection.create(self, section)
m5.uci:save("mwan3") m5.uci:save("mwan3")
luci.http.redirect(ds.build_url("admin", "network", "mwan", "policy", section)) luci.http.redirect(dsp.build_url("admin", "network", "mwan", "policy", section))
end end
use_member = mwan_policy:option(DummyValue, "use_member", translate("Members assigned")) use_member = mwan_policy:option(DummyValue, "use_member", translate("Members assigned"))
use_member.rawhtml = true use_member.rawhtml = true
function use_member.cfgvalue(self, s) function use_member.cfgvalue(self, s)
local memberConfig, memberList = self.map:get(s, "use_member"), "" local memberConfig, memberList = self.map:get(s, "use_member"), ""
if memberConfig then if memberConfig then
for k,v in pairs(memberConfig) do for k,v in pairs(memberConfig) do
memberList = memberList .. v .. "<br />" memberList = memberList .. v .. "<br />"
end
return memberList
else
return "&#8212;"
end end
return memberList
else
return "&#8212;"
end end
end
last_resort = mwan_policy:option(DummyValue, "last_resort", translate("Last resort")) last_resort = mwan_policy:option(DummyValue, "last_resort", translate("Last resort"))
last_resort.rawhtml = true last_resort.rawhtml = true
function last_resort.cfgvalue(self, s) function last_resort.cfgvalue(self, s)
local action = self.map:get(s, "last_resort") local action = self.map:get(s, "last_resort")
if action == "blackhole" then if action == "blackhole" then
return translate("blackhole (drop)") return translate("blackhole (drop)")
elseif action == "default" then elseif action == "default" then
return translate("default (use main routing table)") return translate("default (use main routing table)")
else else
return translate("unreachable (reject)") return translate("unreachable (reject)")
end
end end
end
errors = mwan_policy:option(DummyValue, "errors", translate("Errors"))
errors.rawhtml = true
function errors.cfgvalue(self, s)
if not string.find(err_name_list, " " .. s .. " ") then
return ""
else
return "<span title=\"Name exceeds 15 characters\"><img src=\"/luci-static/resources/cbi/reset.gif\" alt=\"error\"></img></span>"
end
end
return m5 return m5

View file

@ -1,65 +1,26 @@
-- ------ extra functions ------ --
function policyCheck() -- check to see if this policy's name exceed the maximum of 15 characters
policyNameLength = string.len(arg[1])
if policyNameLength > 15 then
nameTooLong = 1
end
end
function policyWarn() -- display status and warning messages at the top of the page
if nameTooLong == 1 then
return "<font color=\"ff0000\"><strong>" .. translatef("WARNING: This policy's name is %d characters exceeding the maximum of 15!", policyNameLength) .. "</strong></font>"
else
return ""
end
end
function cbiAddMember(field)
uci.cursor():foreach("mwan3", "member",
function (section)
field:value(section[".name"])
end
)
end
-- ------ policy configuration ------ --
dsp = require "luci.dispatcher" dsp = require "luci.dispatcher"
arg[1] = arg[1] or "" arg[1] = arg[1] or ""
nameTooLong = 0
policyCheck()
m5 = Map("mwan3", translatef("MWAN Policy Configuration - %s", arg[1]),
policyWarn())
m5.redirect = dsp.build_url("admin", "network", "mwan", "policy")
m5 = Map("mwan3", translatef("MWAN Policy Configuration - %s", arg[1]))
m5.redirect = dsp.build_url("admin", "network", "mwan", "policy")
mwan_policy = m5:section(NamedSection, arg[1], "policy", "") mwan_policy = m5:section(NamedSection, arg[1], "policy", "")
mwan_policy.addremove = false mwan_policy.addremove = false
mwan_policy.dynamic = false mwan_policy.dynamic = false
member = mwan_policy:option(DynamicList, "use_member", translate("Member used"))
use_member = mwan_policy:option(DynamicList, "use_member", translate("Member used")) m5.uci:foreach("mwan3", "member",
cbiAddMember(use_member) function(s)
member:value(s['.name'], s['.name'])
end
)
last_resort = mwan_policy:option(ListValue, "last_resort", translate("Last resort"), last_resort = mwan_policy:option(ListValue, "last_resort", translate("Last resort"),
translate("When all policy members are offline use this behavior for matched traffic")) translate("When all policy members are offline use this behavior for matched traffic"))
last_resort.default = "unreachable" last_resort.default = "unreachable"
last_resort:value("unreachable", translate("unreachable (reject)")) last_resort:value("unreachable", translate("unreachable (reject)"))
last_resort:value("blackhole", translate("blackhole (drop)")) last_resort:value("blackhole", translate("blackhole (drop)"))
last_resort:value("default", translate("default (use main routing table)")) last_resort:value("default", translate("default (use main routing table)"))
-- ------ currently configured members ------ --
mwan_member = m5:section(TypedSection, "member", translate("Currently Configured Members"))
mwan_member.addremove = false
mwan_member.dynamic = false
mwan_member.sortable = false
mwan_member.template = "cbi/tblsection"
return m5 return m5

View file

@ -1,141 +1,99 @@
-- ------ extra functions ------ -- dsp = require "luci.dispatcher"
function ruleCheck() -- determine if rules needs a proper protocol configured
function ruleCheck()
local rule_error = {}
uci.cursor():foreach("mwan3", "rule", uci.cursor():foreach("mwan3", "rule",
function (section) function (section)
local sourcePort = ut.trim(sys.exec("uci -p /var/state get mwan3." .. section[".name"] .. ".src_port")) rule_error[section[".name"]] = false
local destPort = ut.trim(sys.exec("uci -p /var/state get mwan3." .. section[".name"] .. ".dest_port")) local uci = uci.cursor(nil, "/var/state")
if sourcePort ~= "" or destPort ~= "" then -- ports configured local sourcePort = uci:get("mwan3", section[".name"], "src_port")
local protocol = ut.trim(sys.exec("uci -p /var/state get mwan3." .. section[".name"] .. ".proto")) local destPort = uci:get("mwan3", section[".name"], "dest_port")
if protocol == "" or protocol == "all" then -- no or improper protocol if sourcePort ~= nil or destPort ~= nil then
error_protocol_list = error_protocol_list .. section[".name"] .. " " local protocol = uci:get("mwan3", section[".name"], "proto")
if protocol == nil or protocol == "all" then
rule_error[section[".name"]] = true
end end
end end
end end
) )
return rule_error
end end
function ruleWarn() -- display warning messages at the top of the page function ruleWarn(rule_error)
if error_protocol_list ~= " " then local warnings = ""
return "<font color=\"ff0000\"><strong>" .. translate("WARNING: Some rules have a port configured with no or improper protocol specified! Please configure a specific protocol!") .. "</strong></font>" for i, k in pairs(rule_error) do
else if rule_error[i] == true then
return "" warnings = warnings .. string.format("<strong>%s</strong></br>",
translatef("WARNING: Rule %s have a port configured with no or improper protocol specified!", i)
)
end
end end
return warnings
end end
-- ------ rule configuration ------ -- m5 = Map("mwan3", translate("MWAN - Rules"),
ruleWarn(ruleCheck())
)
dsp = require "luci.dispatcher" mwan_rule = m5:section(TypedSection, "rule", nil,
sys = require "luci.sys" translate("Rules specify which traffic will use a particular MWAN policy<br />" ..
ut = require "luci.util" "Rules are based on IP address, port or protocol<br />" ..
"Rules are matched from top to bottom<br />" ..
error_protocol_list = " " "Rules below a matching rule are ignored<br />" ..
ruleCheck() "Traffic not matching any rule is routed using the main routing table<br />" ..
"Traffic destined for known (other than default) networks is handled by the main routing table<br />" ..
"Traffic matching a rule, but all WAN interfaces for that policy are down will be blackholed<br />" ..
m5 = Map("mwan3", translate("MWAN Rule Configuration"),
ruleWarn())
m5:append(Template("mwan/config_css"))
mwan_rule = m5:section(TypedSection, "rule", translate("Traffic Rules"),
translate("Rules specify which traffic will use a particular MWAN policy based on IP address, port or protocol<br />" ..
"Rules are matched from top to bottom. Rules below a matching rule are ignored. Traffic not matching any rule is routed using the main routing table<br />" ..
"Traffic destined for known (other than default) networks is handled by the main routing table. Traffic matching a rule, but all WAN interfaces for that policy are down will be blackholed<br />" ..
"Names may contain characters A-Z, a-z, 0-9, _ and no spaces<br />" .. "Names may contain characters A-Z, a-z, 0-9, _ and no spaces<br />" ..
"Rules may not share the same name as configured interfaces, members or policies")) "Rules may not share the same name as configured interfaces, members or policies"))
mwan_rule.addremove = true mwan_rule.addremove = true
mwan_rule.anonymous = false mwan_rule.anonymous = false
mwan_rule.dynamic = false mwan_rule.dynamic = false
mwan_rule.sectionhead = translate("Rule") mwan_rule.sectionhead = translate("Rule")
mwan_rule.sortable = true mwan_rule.sortable = true
mwan_rule.template = "cbi/tblsection" mwan_rule.template = "cbi/tblsection"
mwan_rule.extedit = dsp.build_url("admin", "network", "mwan", "rule", "%s") mwan_rule.extedit = dsp.build_url("admin", "network", "mwan", "rule", "%s")
function mwan_rule.create(self, section) function mwan_rule.create(self, section)
TypedSection.create(self, section) TypedSection.create(self, section)
m5.uci:save("mwan3") m5.uci:save("mwan3")
luci.http.redirect(dsp.build_url("admin", "network", "mwan", "rule", section)) luci.http.redirect(dsp.build_url("admin", "network", "mwan", "rule", section))
end end
src_ip = mwan_rule:option(DummyValue, "src_ip", translate("Source address")) src_ip = mwan_rule:option(DummyValue, "src_ip", translate("Source address"))
src_ip.rawhtml = true src_ip.rawhtml = true
function src_ip.cfgvalue(self, s) function src_ip.cfgvalue(self, s)
return self.map:get(s, "src_ip") or "&#8212;" return self.map:get(s, "src_ip") or "&#8212;"
end end
src_port = mwan_rule:option(DummyValue, "src_port", translate("Source port")) src_port = mwan_rule:option(DummyValue, "src_port", translate("Source port"))
src_port.rawhtml = true src_port.rawhtml = true
function src_port.cfgvalue(self, s) function src_port.cfgvalue(self, s)
return self.map:get(s, "src_port") or "&#8212;" return self.map:get(s, "src_port") or "&#8212;"
end end
dest_ip = mwan_rule:option(DummyValue, "dest_ip", translate("Destination address")) dest_ip = mwan_rule:option(DummyValue, "dest_ip", translate("Destination address"))
dest_ip.rawhtml = true dest_ip.rawhtml = true
function dest_ip.cfgvalue(self, s) function dest_ip.cfgvalue(self, s)
return self.map:get(s, "dest_ip") or "&#8212;" return self.map:get(s, "dest_ip") or "&#8212;"
end end
dest_port = mwan_rule:option(DummyValue, "dest_port", translate("Destination port")) dest_port = mwan_rule:option(DummyValue, "dest_port", translate("Destination port"))
dest_port.rawhtml = true dest_port.rawhtml = true
function dest_port.cfgvalue(self, s) function dest_port.cfgvalue(self, s)
return self.map:get(s, "dest_port") or "&#8212;" return self.map:get(s, "dest_port") or "&#8212;"
end end
proto = mwan_rule:option(DummyValue, "proto", translate("Protocol")) proto = mwan_rule:option(DummyValue, "proto", translate("Protocol"))
proto.rawhtml = true proto.rawhtml = true
function proto.cfgvalue(self, s) function proto.cfgvalue(self, s)
return self.map:get(s, "proto") or "all" return self.map:get(s, "proto") or "all"
end end
sticky = mwan_rule:option(DummyValue, "sticky", translate("Sticky"))
sticky.rawhtml = true
function sticky.cfgvalue(self, s)
if self.map:get(s, "sticky") == "1" then
stickied = 1
return translate("Yes")
else
stickied = nil
return translate("No")
end
end
timeout = mwan_rule:option(DummyValue, "timeout", translate("Sticky timeout"))
timeout.rawhtml = true
function timeout.cfgvalue(self, s)
if stickied then
local timeoutValue = self.map:get(s, "timeout")
if timeoutValue then
return timeoutValue .. "s"
else
return "600s"
end
else
return "&#8212;"
end
end
ipset = mwan_rule:option(DummyValue, "ipset", translate("IPset"))
ipset.rawhtml = true
function ipset.cfgvalue(self, s)
return self.map:get(s, "ipset") or "&#8212;"
end
use_policy = mwan_rule:option(DummyValue, "use_policy", translate("Policy assigned")) use_policy = mwan_rule:option(DummyValue, "use_policy", translate("Policy assigned"))
use_policy.rawhtml = true use_policy.rawhtml = true
function use_policy.cfgvalue(self, s) function use_policy.cfgvalue(self, s)
return self.map:get(s, "use_policy") or "&#8212;" return self.map:get(s, "use_policy") or "&#8212;"
end end
errors = mwan_rule:option(DummyValue, "errors", translate("Errors"))
errors.rawhtml = true
function errors.cfgvalue(self, s)
if not string.find(error_protocol_list, " " .. s .. " ") then
return ""
else
return "<span title=\"" .. translate("No protocol specified") .. "\"><img src=\"/luci-static/resources/cbi/reset.gif\" alt=\"error\"></img></span>"
end
end
return m5 return m5

View file

@ -1,113 +1,59 @@
-- ------ extra functions ------ --
function ruleCheck() -- determine if rule needs a protocol specified
local sourcePort = ut.trim(sys.exec("uci -p /var/state get mwan3." .. arg[1] .. ".src_port"))
local destPort = ut.trim(sys.exec("uci -p /var/state get mwan3." .. arg[1] .. ".dest_port"))
if sourcePort ~= "" or destPort ~= "" then -- ports configured
local protocol = ut.trim(sys.exec("uci -p /var/state get mwan3." .. arg[1] .. ".proto"))
if protocol == "" or protocol == "all" then -- no or improper protocol
error_protocol = 1
end
end
end
function ruleWarn() -- display warning message at the top of the page
if error_protocol == 1 then
return "<font color=\"ff0000\"><strong>" .. translate("WARNING: This rule is incorrectly configured with no or improper protocol specified! Please configure a specific protocol!") .. "</strong></font>"
else
return ""
end
end
function cbiAddPolicy(field)
uci.cursor():foreach("mwan3", "policy",
function (section)
field:value(section[".name"])
end
)
end
function cbiAddProtocol(field)
local protocols = ut.trim(sys.exec("cat /etc/protocols | grep ' # ' | awk '{print $1}' | grep -vw -e 'ip' -e 'tcp' -e 'udp' -e 'icmp' -e 'esp' | grep -v 'ipv6' | sort | tr '\n' ' '"))
for p in string.gmatch(protocols, "%S+") do
field:value(p)
end
end
-- ------ rule configuration ------ --
dsp = require "luci.dispatcher" dsp = require "luci.dispatcher"
sys = require "luci.sys"
ut = require "luci.util"
arg[1] = arg[1] or "" arg[1] = arg[1] or ""
error_protocol = 0
ruleCheck()
m5 = Map("mwan3", translatef("MWAN Rule Configuration - %s", arg[1]),
ruleWarn())
m5.redirect = dsp.build_url("admin", "network", "mwan", "rule")
m5 = Map("mwan3", translatef("MWAN Rule Configuration - %s", arg[1]))
m5.redirect = dsp.build_url("admin", "network", "mwan", "rule")
mwan_rule = m5:section(NamedSection, arg[1], "rule", "") mwan_rule = m5:section(NamedSection, arg[1], "rule", "")
mwan_rule.addremove = false mwan_rule.addremove = false
mwan_rule.dynamic = false mwan_rule.dynamic = false
src_ip = mwan_rule:option(Value, "src_ip", translate("Source address"), src_ip = mwan_rule:option(Value, "src_ip", translate("Source address"),
translate("Supports CIDR notation (eg \"192.168.100.0/24\") without quotes")) translate("Supports CIDR notation (eg \"192.168.100.0/24\") without quotes"))
src_ip.datatype = ipaddr src_ip.datatype = ipaddr
src_port = mwan_rule:option(Value, "src_port", translate("Source port"), src_port = mwan_rule:option(Value, "src_port", translate("Source port"),
translate("May be entered as a single or multiple port(s) (eg \"22\" or \"80,443\") or as a portrange (eg \"1024:2048\") without quotes")) translate("May be entered as a single or multiple port(s) (eg \"22\" or \"80,443\") or as a portrange (eg \"1024:2048\") without quotes"))
dest_ip = mwan_rule:option(Value, "dest_ip", translate("Destination address"), dest_ip = mwan_rule:option(Value, "dest_ip", translate("Destination address"),
translate("Supports CIDR notation (eg \"192.168.100.0/24\") without quotes")) translate("Supports CIDR notation (eg \"192.168.100.0/24\") without quotes"))
dest_ip.datatype = ipaddr dest_ip.datatype = ipaddr
dest_port = mwan_rule:option(Value, "dest_port", translate("Destination port"), dest_port = mwan_rule:option(Value, "dest_port", translate("Destination port"),
translate("May be entered as a single or multiple port(s) (eg \"22\" or \"80,443\") or as a portrange (eg \"1024:2048\") without quotes")) translate("May be entered as a single or multiple port(s) (eg \"22\" or \"80,443\") or as a portrange (eg \"1024:2048\") without quotes"))
proto = mwan_rule:option(Value, "proto", translate("Protocol"), proto = mwan_rule:option(Value, "proto", translate("Protocol"),
translate("View the contents of /etc/protocols for protocol descriptions")) translate("View the content of /etc/protocols for protocol description"))
proto.default = "all" proto.default = "all"
proto.rmempty = false proto.rmempty = false
proto:value("all") proto:value("all")
proto:value("ip") proto:value("tcp")
proto:value("tcp") proto:value("udp")
proto:value("udp") proto:value("icmp")
proto:value("icmp") proto:value("esp")
proto:value("esp")
cbiAddProtocol(proto)
sticky = mwan_rule:option(ListValue, "sticky", translate("Sticky"), sticky = mwan_rule:option(ListValue, "sticky", translate("Sticky"),
translate("Traffic from the same source IP address that previously matched this rule within the sticky timeout period will use the same WAN interface")) translate("Traffic from the same source IP address that previously matched this rule within the sticky timeout period will use the same WAN interface"))
sticky.default = "0" sticky.default = "0"
sticky:value("1", translate("Yes")) sticky:value("1", translate("Yes"))
sticky:value("0", translate("No")) sticky:value("0", translate("No"))
timeout = mwan_rule:option(Value, "timeout", translate("Sticky timeout"), timeout = mwan_rule:option(Value, "timeout", translate("Sticky timeout"),
translate("Seconds. Acceptable values: 1-1000000. Defaults to 600 if not set")) translate("Seconds. Acceptable values: 1-1000000. Defaults to 600 if not set"))
timeout.datatype = "range(1, 1000000)" timeout.datatype = "range(1, 1000000)"
ipset = mwan_rule:option(Value, "ipset", translate("IPset"), ipset = mwan_rule:option(Value, "ipset", translate("IPset"),
translate("Name of IPset rule. Requires IPset rule in /etc/dnsmasq.conf (eg \"ipset=/youtube.com/youtube\")")) translate("Name of IPset rule. Requires IPset rule in /etc/dnsmasq.conf (eg \"ipset=/youtube.com/youtube\")"))
use_policy = mwan_rule:option(Value, "use_policy", translate("Policy assigned")) policy = mwan_rule:option(Value, "use_policy", translate("Policy assigned"))
cbiAddPolicy(use_policy) m5.uci:foreach("mwan3", "policy",
use_policy:value("unreachable", translate("unreachable (reject)")) function(s)
use_policy:value("blackhole", translate("blackhole (drop)")) policy:value(s['.name'], s['.name'])
use_policy:value("default", translate("default (use main routing table)")) end
)
policy:value("unreachable", translate("unreachable (reject)"))
-- ------ currently configured policies ------ -- policy:value("blackhole", translate("blackhole (drop)"))
policy:value("default", translate("default (use main routing table)"))
mwan_policy = m5:section(TypedSection, "policy", translate("Currently Configured Policies"))
mwan_policy.addremove = false
mwan_policy.dynamic = false
mwan_policy.sortable = false
mwan_policy.template = "cbi/tblsection"
return m5 return m5

View file

@ -1 +1 @@
<%+mwan/openwrt_overview_status%> <%+mwan/overview_status_interface%>

View file

@ -1,28 +0,0 @@
<style type="text/css">
table td { /* cells showing the configuration values */
padding: 0px;
text-align: center;
vertical-align: middle;
}
table th { /* column for configuration section name */
padding: 0px;
text-align: center;
vertical-align: middle;
}
table tbody th { /* column for configuration section name */
padding: 0px;
vertical-align: middle;
}
.cbi-section-node table div { /* rows */
padding-top: 5px;
}
table.cbi-section-table td.cbi-section-table-cell { /* sort buttons column */
text-align: center;
}
.cbi-section h3 {
color: rgb(85, 85, 85);
font-family: Trebuchet MS,Verdana,sans-serif;
font-style: italic;
font-weight: normal;
}
</style>

View file

@ -1,44 +1,46 @@
<script type="text/javascript">//<![CDATA[ <script type="text/javascript">//<![CDATA[
XHR.poll(5, '<%=luci.dispatcher.build_url("admin", "status", "mwan", "interface_status")%>', null, XHR.poll(5, '<%=luci.dispatcher.build_url("admin", "status", "mwan", "interface_status")%>', null,
function(x, mArray) function(x, status)
{ {
var status = document.getElementById('mwan_status_text'); var statusDiv = document.getElementById('mwan_status_text');
if (mArray.wans) if (status.interfaces)
{ {
var temp = ''; var statusview = '';
for ( var i = 0; i < mArray.wans.length; i++ ) for ( var iface in status.interfaces)
{ {
var stat = ''; var state = '';
var cssc = ''; var css = '';
switch (mArray.wans[i].status) switch (status.interfaces[iface].status)
{ {
case 'online': case 'online':
stat = '<%:Online (tracking active)%>'; state = '<%:Online (tracking active)%>';
cssc = 'wanon'; css = 'wanon';
break; break;
case 'notMonitored': case 'notMonitored':
stat = '<%:Online (tracking off)%>'; state = '<%:Online (tracking off)%>';
cssc = 'wanon'; css = 'wanon';
break; break;
case 'offline': case 'offline':
stat = '<%:Offline%>'; state = '<%:Offline%>';
cssc = 'wanoff'; css = 'wanoff';
break; break;
case 'notEnabled': default:
stat = '<%:Disabled%>'; state = '<%:Disabled%>';
cssc = 'wanoff'; css = 'wanoff';
break; break;
} }
temp += String.format( statusview += String.format(
'<span class="%s"><strong>%s (<a href="%q">%s</a>)</strong><br />%s</span>', '<span class="%s"><strong>%s</strong><br />%s</span>',
cssc, mArray.wans[i].name, mArray.wans[i].link, mArray.wans[i].ifname, stat css,
iface,
state
); );
} }
status.innerHTML = temp; statusDiv.innerHTML = statusview;
} }
else else
{ {
status.innerHTML = '<strong><%:No MWAN interfaces found%></strong>'; statusDiv.innerHTML = '<strong><%:No MWAN interfaces found%></strong>';
} }
} }
); );

View file

@ -1,8 +1,8 @@
<%+header%> <%+header%>
<ul class="cbi-tabmenu"> <ul class="cbi-tabmenu">
<li class="cbi-tab-disabled"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/overview")%>"><%:Interface Status%></a></li> <li class="cbi-tab-disabled"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/overview")%>"><%:Interface%></a></li>
<li class="cbi-tab"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/detail")%>"><%:Detailed Status%></a></li> <li class="cbi-tab"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/detail")%>"><%:Detail%></a></li>
<li class="cbi-tab-disabled"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/diagnostics")%>"><%:Diagnostics%></a></li> <li class="cbi-tab-disabled"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/diagnostics")%>"><%:Diagnostics%></a></li>
<li class="cbi-tab-disabled"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/troubleshooting")%>"><%:Troubleshooting%></a></li> <li class="cbi-tab-disabled"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/troubleshooting")%>"><%:Troubleshooting%></a></li>
</ul> </ul>
@ -10,33 +10,24 @@
<script type="text/javascript" src="<%=resource%>/cbi.js"></script> <script type="text/javascript" src="<%=resource%>/cbi.js"></script>
<script type="text/javascript">//<![CDATA[ <script type="text/javascript">//<![CDATA[
XHR.poll(5, '<%=luci.dispatcher.build_url("admin", "status", "mwan", "detailed_status")%>', null, XHR.poll(5, '<%=luci.dispatcher.build_url("admin", "status", "mwan", "detailed_status")%>', null,
function(x, mArray) function(x)
{ {
var status = document.getElementById('mwan_detail_text'); var legend = document.getElementById('diag-rc-legend');
if (mArray.mwandetail) var output = document.getElementById('diag-rc-output');
{ legend.style.display = 'none';
status.innerHTML = String.format('<pre>%s</pre>', mArray.mwandetail[0]); output.innerHTML = String.format('<pre>%h</pre>', x.responseText);
}
else
{
status.innerHTML = '<strong><%:No detailed status information available%></strong>';
}
} }
); );
//]]></script> //]]></script>
<div id="mwan_detail_status"> <div class="cbi-map">
<h2 name="content"><%:MWAN Status - Detail%></h2>
<fieldset class="cbi-section"> <fieldset class="cbi-section">
<legend><%:MWAN Detailed Status%></legend> <legend id="diag-rc-legend"><%:Collecting data...%></legend>
<div id="mwan_detail_text"><img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align:middle" /><%:Collecting data...%></div> <span id="diag-rc-output">
<img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align: middle;" />
</span>
</fieldset> </fieldset>
</div> </div>
<style type="text/css">
#mwan_detail_text {
padding: 20px;
text-align: left;
}
</style>
<%+footer%> <%+footer%>

View file

@ -1,8 +1,8 @@
<%+header%> <%+header%>
<ul class="cbi-tabmenu"> <ul class="cbi-tabmenu">
<li class="cbi-tab-disabled"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/overview")%>"><%:Interface Status%></a></li> <li class="cbi-tab-disabled"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/overview")%>"><%:Interface%></a></li>
<li class="cbi-tab-disabled"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/detail")%>"><%:Detailed Status%></a></li> <li class="cbi-tab-disabled"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/detail")%>"><%:Detail%></a></li>
<li class="cbi-tab"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/diagnostics")%>"><%:Diagnostics%></a></li> <li class="cbi-tab"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/diagnostics")%>"><%:Diagnostics%></a></li>
<li class="cbi-tab-disabled"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/troubleshooting")%>"><%:Troubleshooting%></a></li> <li class="cbi-tab-disabled"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/troubleshooting")%>"><%:Troubleshooting%></a></li>
</ul> </ul>
@ -10,10 +10,11 @@
<% <%
local uci = require "luci.model.uci" local uci = require "luci.model.uci"
interfaceNames = "" local iface = {}
uci.cursor():foreach("mwan3", "interface", uci.cursor():foreach("mwan3", "interface",
function (section) function (section)
interfaceNames = interfaceNames .. section[".name"] .. " " table.insert(iface, section[".name"])
end end
) )
%> %>
@ -22,92 +23,64 @@
<script type="text/javascript">//<![CDATA[ <script type="text/javascript">//<![CDATA[
var stxhr = new XHR(); var stxhr = new XHR();
function update_status(tool, task, task_name) function update_status(iface, task)
{ {
var iface = document.getElementById('mwaniface').value; var legend = document.getElementById('diag-rc-legend');
var output = document.getElementById('diag_output'); var output = document.getElementById('diag-rc-output');
if (tool == "service") output.innerHTML =
{ '<img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align: middle;" />' +
output.innerHTML = "<%:Waiting for command to complete...%>"
'<img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="padding: 20px; vertical-align: middle;" /> ' + ;
String.format("<%:Waiting for MWAN to %s...%>", task_name)
;
}
else
{
output.innerHTML =
'<img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="padding: 20px; vertical-align: middle;" /> ' +
"<%:Waiting for diagnostic results...%>"
;
}
output.parentNode.style.display = 'block'; output.parentNode.style.display = 'block';
output.style.display = 'inline'; output.style.display = 'inline';
stxhr.get('<%=luci.dispatcher.build_url("admin", "status", "mwan")%>/diagnostics_display' + '/' + iface + '/' + tool + '/' + task, null, stxhr.post('<%=url('admin/status/mwan')%>/diagnostics_display' + '/' + iface + '/' + task, { token: '<%=token%>' },
function(x, mArray) function(x)
{ {
if (mArray.diagnostics) legend.style.display = 'none';
{ output.innerHTML = String.format('<pre>%h</pre>', x.responseText);
output.innerHTML = String.format('<pre id="diag_output_css">%h</pre>', mArray.diagnostics[0]);
}
else
{
output.innerHTML = '<pre id="diag_output_css"><strong><%:No diagnostic results returned%></strong></pre>';
}
} }
); );
} }
//]]></script> //]]></script>
<div id="mwan_diagnostics" class="cbi-map"> <form method="post" action="<%=url('admin/network/diagnostics')%>">
<fieldset id="diag_select" class="cbi-section"> <div class="cbi-map">
<legend><%:MWAN Interface Diagnostics%></legend> <h2 name="content"><%:MWAN Status - Diagnostics%></h2>
<select id="mwaniface">
<% for z in interfaceNames:gmatch("[^ ]+") do -%><option value="<%=z%>"><%=z%></option><%- end %>
</select>
<div id="buttoncss">
<input type="button" value="<%:Ping default gateway%>" class="cbi-button cbi-button-apply" onclick="update_status('ping', 'gateway', null)" />
<input type="button" value="<%:Ping tracking IP%>" class="cbi-button cbi-button-apply" onclick="update_status('ping', 'track_ip', null)" />
<input type="button" value="<%:Check IP rules%>" class="cbi-button cbi-button-apply" onclick="update_status('rulechk', null, null)" />
<input type="button" value="<%:Check routing table%>" class="cbi-button cbi-button-apply" onclick="update_status('routechk', null, null)" />
<input type="button" value="<%:Hotplug ifup%>" class="cbi-button cbi-button-apply" onclick="update_status('hotplug', 'ifup', null)" />
<input type="button" value="<%:Hotplug ifdown%>" class="cbi-button cbi-button-apply" onclick="update_status('hotplug', 'ifdown', null)" />
</div>
</fieldset>
<fieldset id="diag_select" class="cbi-section">
<legend><%:MWAN Service Control%></legend>
<div id="buttoncss">
<input type="button" value="<%:Restart MWAN%>" class="cbi-button cbi-button-apply" onclick="update_status('service', 'restart', '<%:restart%>')" />
<input type="button" value="<%:Stop MWAN%>" class="cbi-button cbi-button-apply" onclick="update_status('service', 'stop', '<%:stop%>')" />
<input type="button" value="<%:Start MWAN%>" class="cbi-button cbi-button-apply" onclick="update_status('service', 'start', '<%:start%>')" />
</div>
</fieldset>
<fieldset class="cbi-section" style="display:none">
<legend><%:Diagnostic Results%></legend>
<div id="diag_output"></div>
</fieldset>
</div>
<style type="text/css"> <fieldset class="cbi-section">
#mwaniface { <br />
float: left;
margin: 8px 20px 0px 0px; <div style="width:30%; float:left">
} <label class="cbi-value-title"><%:Interface%></label>
#buttoncss { <select name="iface" style="width:auto">
display: table; <% for _, z in ipairs(iface) do -%><option value="<%=z%>"><%=z%></option><%- end %>
float: left; </select>
text-align: left; </div>
}
.cbi-button { <div style="width:30%; float:left">
margin: 8px 20px 0px 0px; <label class="cbi-value-title"><%:Task%></label>
min-width: 153px; <select name="task" style="width:auto">
} <option value="ping_gateway"><%:Ping default gateway%></option>
#diag_output_css { <option value="ping_trackips"><%:Ping tracking IP%></option>
padding: 20px; <option value="check_rules"><%:Check IP rules%></option>
text-align: left; <option value="check_routes"><%:Check routing table%></option>
} <option value="hotplug_ifup"><%:Hotplug ifup%>"</option>
</style> <option value="hotplug_ifdown"><%:Hotplug ifdown%></option>
</select>
</div>
<div style="width:30%; float:left">
<input type="button" value="<%:Execute%>" class="cbi-button cbi-button-apply" onclick="update_status(this.form.iface.value, this.form.task.value)"/>
</div>
</fieldset>
</div>
<fieldset class="cbi-section" style="display:none">
<legend id="diag-rc-legend"><%:Collecting data...%></legend>
<span id="diag-rc-output"></span>
</fieldset>
</form>
<%+footer%> <%+footer%>

View file

@ -1,8 +1,8 @@
<%+header%> <%+header%>
<ul class="cbi-tabmenu"> <ul class="cbi-tabmenu">
<li class="cbi-tab"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/overview")%>"><%:Interface Status%></a></li> <li class="cbi-tab"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/overview")%>"><%:Interface%></a></li>
<li class="cbi-tab-disabled"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/detail")%>"><%:Detailed Status%></a></li> <li class="cbi-tab-disabled"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/detail")%>"><%:Detail%></a></li>
<li class="cbi-tab-disabled"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/diagnostics")%>"><%:Diagnostics%></a></li> <li class="cbi-tab-disabled"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/diagnostics")%>"><%:Diagnostics%></a></li>
<li class="cbi-tab-disabled"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/troubleshooting")%>"><%:Troubleshooting%></a></li> <li class="cbi-tab-disabled"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/troubleshooting")%>"><%:Troubleshooting%></a></li>
</ul> </ul>
@ -10,70 +10,57 @@
<script type="text/javascript" src="<%=resource%>/cbi.js"></script> <script type="text/javascript" src="<%=resource%>/cbi.js"></script>
<script type="text/javascript">//<![CDATA[ <script type="text/javascript">//<![CDATA[
XHR.poll(5, '<%=luci.dispatcher.build_url("admin", "status", "mwan", "interface_status")%>', null, XHR.poll(5, '<%=luci.dispatcher.build_url("admin", "status", "mwan", "interface_status")%>', null,
function(x, mArray) function(x, status)
{ {
var statusDiv = document.getElementById('mwan_status_text'); var statusDiv = document.getElementById('mwan_status_text');
if (mArray.wans) if (status.interfaces)
{ {
var interfaceStatus = ''; var statusview = '';
for ( var i = 0; i < mArray.wans.length; i++ ) for ( var iface in status.interfaces)
{ {
var status = ''; var state = '';
var css = ''; var css = '';
switch (mArray.wans[i].status) switch (status.interfaces[iface].status)
{ {
case 'online': case 'online':
status = '<%:Online (tracking active)%>'; state = '<%:Online (tracking active)%>';
css = 'wanon'; css = 'wanon';
break; break;
case 'notMonitored': case 'notMonitored':
status = '<%:Online (tracking off)%>'; state = '<%:Online (tracking off)%>';
css = 'wanon'; css = 'wanon';
break; break;
case 'offline': case 'offline':
status = '<%:Offline%>'; state = '<%:Offline%>';
css = 'wanoff'; css = 'wanoff';
break; break;
case 'notEnabled': default:
status = '<%:Disabled%>'; state = '<%:Disabled%>';
css = 'wanoff'; css = 'wanoff';
break; break;
} }
interfaceStatus += String.format( statusview += String.format(
'<span class="%s"><strong>%s (<a href="%q">%s</a>)</strong><br />%s</span>', '<span class="%s"><strong>%s</strong><br />%s</span>',
css, mArray.wans[i].name, mArray.wans[i].link, mArray.wans[i].ifname, status css,
iface,
state
); );
} }
statusDiv.innerHTML = interfaceStatus; statusDiv.innerHTML = statusview;
} }
else else
{ {
statusDiv.innerHTML = '<strong><%:No MWAN interfaces found%></strong>'; statusDiv.innerHTML = '<strong><%:No MWAN interfaces found%></strong>';
} }
var logs = document.getElementById('mwan_statuslog_text');
if (mArray.mwanlog)
{
var mwanLog = '<%:Last 50 MWAN systemlog entries. Newest entries sorted at the top :%>';
logs.innerHTML = String.format('<pre>%s<br /><br />%s</pre>', mwanLog, mArray.mwanlog[0]);
}
else
{
logs.innerHTML = '<strong><%:No MWAN systemlog history found%></strong>';
}
} }
); );
//]]></script> //]]></script>
<div id="mwan_interface_status"> <div id="mwan_interface_status">
<fieldset id="interface_field" class="cbi-section"> <fieldset id="interface_field" class="cbi-section">
<legend><%:MWAN Interface Live Status%></legend> <legend><%:MWAN status - Interface Live Status%></legend>
<div id="mwan_status_text"><img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align:middle" /><%:Collecting data...%></div> <div id="mwan_status_text"><img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align:middle" /><%:Collecting data...%></div>
</fieldset> </fieldset>
<fieldset class="cbi-section">
<legend><%:MWAN Interface Systemlog%></legend>
<div id="mwan_statuslog_text"><img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align:middle" /><%:Collecting data...%></div>
</fieldset>
</div> </div>
<style type="text/css"> <style type="text/css">

View file

@ -1,8 +1,8 @@
<%+header%> <%+header%>
<ul class="cbi-tabmenu"> <ul class="cbi-tabmenu">
<li class="cbi-tab-disabled"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/overview")%>"><%:Interface Status%></a></li> <li class="cbi-tab-disabled"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/overview")%>"><%:Interface%></a></li>
<li class="cbi-tab-disabled"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/detail")%>"><%:Detailed Status%></a></li> <li class="cbi-tab-disabled"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/detail")%>"><%:Detail%></a></li>
<li class="cbi-tab-disabled"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/diagnostics")%>"><%:Diagnostics%></a></li> <li class="cbi-tab-disabled"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/diagnostics")%>"><%:Diagnostics%></a></li>
<li class="cbi-tab"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/troubleshooting")%>"><%:Troubleshooting%></a></li> <li class="cbi-tab"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/troubleshooting")%>"><%:Troubleshooting%></a></li>
</ul> </ul>
@ -10,52 +10,24 @@
<script type="text/javascript" src="<%=resource%>/cbi.js"></script> <script type="text/javascript" src="<%=resource%>/cbi.js"></script>
<script type="text/javascript">//<![CDATA[ <script type="text/javascript">//<![CDATA[
XHR.poll(15, '<%=luci.dispatcher.build_url("admin", "status", "mwan", "troubleshooting_display")%>', null, XHR.poll(15, '<%=luci.dispatcher.build_url("admin", "status", "mwan", "troubleshooting_display")%>', null,
function(x, mArray) function(x)
{ {
var tshoot = document.getElementById('troubleshoot_text'); var legend = document.getElementById('diag-rc-legend');
if (mArray.versions) var output = document.getElementById('diag-rc-output');
{ legend.style.display = 'none';
var versions = '<span class="description">Software versions : </span><br /><br />'; output.innerHTML = String.format('<pre>%h</pre>', x.responseText);
var mwanConfig = '<br /><br /><span class="description">Output of &#34;cat /etc/config/mwan3&#34; : </span><br /><br />';
var netConfig = '<br /><br /><span class="description">Output of &#34;cat /etc/config/network&#34; : </span><br /><br />';
var wifiConfig = '<br /><br /><span class="description">Output of &#34;cat /etc/config/wireless&#34; : </span><br /><br />';
var ifconfig = '<br /><br /><span class="description">Output of &#34;ifconfig&#34; : </span><br /><br />';
var ipRoute = '<br /><br /><span class="description">Output of &#34;route -n&#34; : </span><br /><br />';
var ipRuleShow = '<br /><br /><span class="description">Output of &#34;ip rule show&#34; : </span><br /><br />';
var routeListTable = '<br /><br /><span class="description">Output of &#34;ip route list table 1-250&#34; : </span><br /><br />';
var firewallOut = '<br /><br /><span class="description">Firewall default output policy (must be ACCEPT) : </span><br /><br />';
var iptables = '<br /><br /><span class="description">Output of &#34;iptables -L -t mangle -v -n&#34; : </span><br /><br />';
tshoot.innerHTML = String.format(
'<pre>%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s</pre>',
versions, mArray.versions[0], mwanConfig, mArray.mwanconfig[0], netConfig, mArray.netconfig[0],
wifiConfig, mArray.wificonfig[0], ifconfig, mArray.ifconfig[0], ipRoute, mArray.routeshow[0],
ipRuleShow, mArray.iprule[0], routeListTable, mArray.routelist[0], firewallOut, mArray.firewallout[0],
iptables, mArray.iptables[0]
);
}
else
{
tshoot.innerHTML = '<strong><%:Error collecting troubleshooting information%></strong>';
}
} }
); );
//]]></script> //]]></script>
<div id="troubleshoot"> <div class="cbi-map">
<h2 name="content"><%:MWAN Status - Troubleshooting%></h2>
<fieldset class="cbi-section"> <fieldset class="cbi-section">
<legend><%:Troubleshooting Data%></legend> <legend id="diag-rc-legend"><%:Collecting data...%></legend>
<div id="troubleshoot_text"><img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align:middle" /><%:Collecting data...%></div> <span id="diag-rc-output">
<img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align: middle;" />
</span>
</fieldset> </fieldset>
</div> </div>
<style type="text/css">
#troubleshoot_text {
padding: 20px;
text-align: left;
}
.description {
background-color: rgb(78, 186, 241);
}
</style>
<%+footer%> <%+footer%>

View file

@ -1,38 +0,0 @@
#!/bin/sh
# to enable this script uncomment the case loop at the bottom
# to report mwan status on interface hotplug ifup/ifdown events modify the lines in the send_alert function
send_alert()
{
# variable "$1" stores the MWAN status information
# insert your code here to send the contents of "$1"
echo "$1"
}
gather_event_info()
{
# create event information message
local EVENT_INFO="Interface [ "$INTERFACE" ($DEVICE) ] on router [ "$(uci -p /var/state get system.@system[0].hostname)" ] has triggered a hotplug [ "$ACTION" ] event on "$(date +"%a %b %d %Y %T %Z")""
# get current interface, policy and rule status
local CURRENT_STATUS="$(/usr/sbin/mwan3 status)"
# get last 50 MWAN systemlog messages
local MWAN_LOG="$(echo -e "Last 50 MWAN systemlog entries. Newest entries sorted at the top:\n$(logread | grep mwan3 | tail -n 50 | sed 'x;1!H;$!d;x')")"
# pass event info to send_alert function
send_alert "$(echo -e "$EVENT_INFO\n\n$CURRENT_STATUS\n\n$MWAN_LOG")"
}
#case "$ACTION" in
# ifup)
# gather_event_info
# ;;
#
# ifdown)
# gather_event_info
# ;;
#esac
exit 0