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 end
luci.http.prepare_content("application/json") function diagnosticsData(interface, task)
luci.http.write_json(mArray) function getInterfaceNumber(interface)
end
function diagnosticsData(interface, tool, task)
function getInterfaceNumber()
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
results = "MWAN3 restarted"
elseif task == "stop" then
results = "MWAN3 stopped"
else
results = "MWAN3 started"
end
else
local interfaceDevice = ut.trim(sys.exec("uci -q -p /var/state get network." .. interface .. ".ifname"))
if interfaceDevice ~= "" then
if tool == "ping" then
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
if results ~= "" then
results = ut.trim(results)
mArray.diagnostics = { results }
end
luci.http.prepare_content("application/json") local uci = uci.cursor(nil, "/var/state")
luci.http.write_json(mArray) local device = uci:get("network", interface, "ifname")
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
luci.http.write("Unknown task")
end
else
luci.http.write(string.format("Unable to perform diagnostic tests on %s.", interface))
luci.http.write("\n")
luci.http.write("There is no physical or virtual device associated with this interface.")
end
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")
luci.http.write(dash)
luci.http.write("\n")
if ver.distversion then
luci.http.write(string.format("OpenWrt - %s", ver.distversion))
luci.http.write("\n")
else else
wrtRelease = "OpenWrt - unknown" luci.http.write("OpenWrt - unknown")
luci.http.write("\n")
end end
local luciRelease = ut.trim(ver.luciversion)
if luciRelease ~= "" then if ver.luciversion then
luciRelease = "\nLuCI - " .. luciRelease luci.http.write(string.format("LuCI - %s", ver.luciversion))
luci.http.write("\n")
else else
luciRelease = "\nLuCI - unknown" luci.http.write("LuCI - unknown")
luci.http.write("\n")
end end
local mwanVersion = ut.trim(sys.exec("opkg info mwan3 | grep Version | awk '{print $2}'"))
if mwanVersion ~= "" then luci.http.write("\n")
mwanVersion = "\n\nmwan3 - " .. mwanVersion luci.http.write("\n")
local output = ut.trim(sys.exec("ip a show"))
luci.http.write("Output of \"ip a show\"")
luci.http.write("\n")
luci.http.write(dash)
luci.http.write("\n")
if output ~= "" then
luci.http.write(output)
luci.http.write("\n")
else else
mwanVersion = "\n\nmwan3 - unknown" luci.http.write("No data found")
luci.http.write("\n")
end end
local mwanLuciVersion = ut.trim(sys.exec("opkg info luci-app-mwan3 | grep Version | awk '{print $2}'"))
if mwanLuciVersion ~= "" then luci.http.write("\n")
mwanLuciVersion = "\nmwan3-luci - " .. mwanLuciVersion luci.http.write("\n")
local output = ut.trim(sys.exec("ip route show"))
luci.http.write("Output of \"ip route show\"")
luci.http.write("\n")
luci.http.write(dash)
luci.http.write("\n")
if output ~= "" then
luci.http.write(output)
luci.http.write("\n")
else else
mwanLuciVersion = "\nmwan3-luci - unknown" luci.http.write("No data found")
luci.http.write("\n")
end end
mArray.versions = { wrtRelease .. luciRelease .. mwanVersion .. mwanLuciVersion }
-- mwan config luci.http.write("\n")
local mwanConfig = ut.trim(sys.exec("cat /etc/config/mwan3")) luci.http.write("\n")
if mwanConfig == "" then local output = ut.trim(sys.exec("ip rule show"))
mwanConfig = "No data found" luci.http.write("Output of \"ip rule show\"")
end luci.http.write("\n")
mArray.mwanconfig = { mwanConfig } luci.http.write(dash)
luci.http.write("\n")
-- network config if output ~= "" then
local networkConfig = ut.trim(sys.exec("cat /etc/config/network | sed -e 's/.*username.*/ USERNAME HIDDEN/' -e 's/.*password.*/ PASSWORD HIDDEN/'")) luci.http.write(output)
if networkConfig == "" then luci.http.write("\n")
networkConfig = "No data found"
end
mArray.netconfig = { networkConfig }
-- wireless config
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/'"))
if wirelessConfig == "" then
wirelessConfig = "No data found"
end
mArray.wificonfig = { wirelessConfig }
-- ifconfig
local ifconfig = ut.trim(sys.exec("ifconfig"))
if ifconfig == "" then
ifconfig = "No data found"
end
mArray.ifconfig = { ifconfig }
-- route -n
local routeShow = ut.trim(sys.exec("route -n"))
if routeShow == "" then
routeShow = "No data found"
end
mArray.routeshow = { routeShow }
-- ip rule show
local ipRuleShow = ut.trim(sys.exec(ip .. "rule show"))
if ipRuleShow == "" then
ipRuleShow = "No data found"
end
mArray.iprule = { ipRuleShow }
-- ip route list table 1-250
local routeList, routeString = ut.trim(sys.exec(ip .. "rule | sed 's/://g' 2>/dev/null | awk '$1>=2001 && $1<=2250' | awk '{print $NF}'")), ""
if routeList ~= "" then
for line in routeList:gmatch("[^\r\n]+") do
routeString = routeString .. line .. "\n" .. sys.exec(ip .. "route list table " .. line)
end
routeString = ut.trim(routeString)
else else
routeString = "No data found" luci.http.write("No data found")
luci.http.write("\n")
end end
mArray.routelist = { routeString }
-- default firewall output policy luci.http.write("\n")
local firewallOut = ut.trim(sys.exec("uci -q -p /var/state get firewall.@defaults[0].output")) luci.http.write("\n")
if firewallOut == "" then luci.http.write("Output of \"ip route list table 1-250\"")
firewallOut = "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 end
mArray.firewallout = { firewallOut }
-- iptables luci.http.write("\n")
local iptables = ut.trim(sys.exec("iptables -L -t mangle -v -n")) luci.http.write("\n")
if iptables == "" then local output = ut.trim(sys.exec("iptables -L -t mangle -v -n"))
iptables = "No data found" luci.http.write("Output of \"iptables -L -t mangle -v -n\"")
luci.http.write("\n")
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 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,109 +1,111 @@
-- ------ 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
if overview[i]["network"] == false then
warnings = warnings .. string.format("<strong>%s</strong></br>",
translatef("WARNING: Interface %s are not found in /etc/config/network", i)
)
end end
if errorRouteList ~= " " then
warnings = warnings .. "<br /><br /><font color=\"ff0000\"><strong>" .. translate("WARNING: Some interfaces have no default route in the main routing table!") .. "</strong></font>" if overview[i]["default_route"] == false then
warnings = warnings .. string.format("<strong>%s</strong></br>",
translatef("WARNING: Interface %s has no default route in the main routing table", i)
)
end end
if errorNetConfigList ~= " " then
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>" 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 end
if errorNoMetricList ~= " " then
warnings = warnings .. "<br /><br /><font color=\"ff0000\"><strong>" .. translate("WARNING: Some interfaces have no metric configured in /etc/config/network!") .. "</strong></font>" 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
if errorDuplicateMetricList ~= " " then
warnings = warnings .. "<br /><br /><font color=\"ff0000\"><strong>" .. translate("WARNING: Some interfaces have duplicate metrics configured in /etc/config/network!") .. "</strong></font>"
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 />" ..
@ -121,35 +123,20 @@ mwan_interface = m5:section(TypedSection, "interface", translate("Interfaces"),
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)
local tracked = self.map:get(s, "track_ip")
if tracked then if tracked then
return self.map:get(s, "track_method") or "&#8212;" return self.map:get(s, "track_method") or "&#8212;"
else else
@ -160,6 +147,7 @@ track_method = mwan_interface:option(DummyValue, "track_method", translate("Trac
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)
local tracked = self.map:get(s, "track_ip")
if tracked then if tracked then
return self.map:get(s, "reliability") or "&#8212;" return self.map:get(s, "reliability") or "&#8212;"
else else
@ -167,34 +155,10 @@ reliability = mwan_interface:option(DummyValue, "reliability", translate("Tracki
end end
end 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
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)
local tracked = self.map:get(s, "track_ip")
if tracked then if tracked then
local intervalValue = self.map:get(s, "interval") local intervalValue = self.map:get(s, "interval")
if intervalValue then if intervalValue then
@ -210,6 +174,7 @@ interval = mwan_interface:option(DummyValue, "interval", translate("Ping interva
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)
local tracked = self.map:get(s, "track_ip")
if tracked then if tracked then
return self.map:get(s, "down") or "&#8212;" return self.map:get(s, "down") or "&#8212;"
else else
@ -220,6 +185,7 @@ down = mwan_interface:option(DummyValue, "down", translate("Interface down"))
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)
local tracked = self.map:get(s, "track_ip")
if tracked then if tracked then
return self.map:get(s, "up") or "&#8212;" return self.map:get(s, "up") or "&#8212;"
else else
@ -230,47 +196,13 @@ up = mwan_interface:option(DummyValue, "up", translate("Interface up"))
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
return metric
else else
return "&#8212;" return "&#8212;"
end 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,102 +1,14 @@
-- ------ 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"))
@ -255,12 +167,13 @@ 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")
if metric then
return metric
else else
return "&#8212;" return "&#8212;"
end end
end end
return m5 return m5

View file

@ -1,13 +1,9 @@
-- ------ 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"))
@ -16,14 +12,13 @@ mwan_member = m5:section(TypedSection, "member", translate("Members"),
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)
@ -42,5 +37,4 @@ weight = mwan_member:option(DummyValue, "weight", translate("Weight"))
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,15 +1,3 @@
-- ------ 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 ""
@ -17,14 +5,16 @@ 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"))
@ -34,14 +24,4 @@ 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,40 +1,38 @@
-- ------ 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 end
-- ------ policy configuration ------ -- return warnings
end
ds = require "luci.dispatcher" m5 = Map("mwan3", translate("MWAN - Policies"),
sys = require "luci.sys" policyError(policyCheck()))
nameTooLong = 0 mwan_policy = m5:section(TypedSection, "policy", nil,
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 />" ..
@ -45,14 +43,13 @@ mwan_policy = m5:section(TypedSection, "policy", translate("Policies"),
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)
@ -80,15 +77,4 @@ last_resort = mwan_policy:option(DummyValue, "last_resort", translate("Last reso
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,49 +1,20 @@
-- ------ 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]))
m5 = Map("mwan3", translatef("MWAN Policy Configuration - %s", arg[1]),
policyWarn())
m5.redirect = dsp.build_url("admin", "network", "mwan", "policy") 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"))
@ -52,14 +23,4 @@ last_resort = mwan_policy:option(ListValue, "last_resort", translate("Last resor
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,47 +1,50 @@
-- ------ 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 end
-- ------ rule configuration ------ -- return warnings
end
dsp = require "luci.dispatcher" m5 = Map("mwan3", translate("MWAN - Rules"),
sys = require "luci.sys" ruleWarn(ruleCheck())
ut = require "luci.util" )
error_protocol_list = " " mwan_rule = m5:section(TypedSection, "rule", nil,
ruleCheck() translate("Rules specify which traffic will use a particular MWAN policy<br />" ..
"Rules are based on IP address, port or protocol<br />" ..
"Rules are matched from top to bottom<br />" ..
m5 = Map("mwan3", translate("MWAN Rule Configuration"), "Rules below a matching rule are ignored<br />" ..
ruleWarn()) "Traffic not matching any rule is routed using the main routing table<br />" ..
m5:append(Template("mwan/config_css")) "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 />" ..
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
@ -57,7 +60,6 @@ mwan_rule = m5:section(TypedSection, "rule", translate("Traffic Rules"),
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)
@ -88,54 +90,10 @@ proto = mwan_rule:option(DummyValue, "proto", translate("Protocol"))
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,60 +1,14 @@
-- ------ 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]))
m5 = Map("mwan3", translatef("MWAN Rule Configuration - %s", arg[1]),
ruleWarn())
m5.redirect = dsp.build_url("admin", "network", "mwan", "rule") 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
@ -70,16 +24,14 @@ 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"))
@ -94,20 +46,14 @@ timeout = mwan_rule:option(Value, "timeout", translate("Sticky timeout"),
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 = output.innerHTML =
'<img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="padding: 20px; vertical-align: middle;" /> ' + '<img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align: middle;" />' +
String.format("<%:Waiting for MWAN to %s...%>", task_name) "<%:Waiting for command to complete...%>"
; ;
}
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 %> <fieldset class="cbi-section">
<br />
<div style="width:30%; float:left">
<label class="cbi-value-title"><%:Interface%></label>
<select name="iface" style="width:auto">
<% for _, z in ipairs(iface) do -%><option value="<%=z%>"><%=z%></option><%- end %>
</select> </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> </div>
<style type="text/css"> <div style="width:30%; float:left">
#mwaniface { <label class="cbi-value-title"><%:Task%></label>
float: left; <select name="task" style="width:auto">
margin: 8px 20px 0px 0px; <option value="ping_gateway"><%:Ping default gateway%></option>
} <option value="ping_trackips"><%:Ping tracking IP%></option>
#buttoncss { <option value="check_rules"><%:Check IP rules%></option>
display: table; <option value="check_routes"><%:Check routing table%></option>
float: left; <option value="hotplug_ifup"><%:Hotplug ifup%>"</option>
text-align: left; <option value="hotplug_ifdown"><%:Hotplug ifdown%></option>
} </select>
.cbi-button { </div>
margin: 8px 20px 0px 0px;
min-width: 153px; <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)"/>
#diag_output_css { </div>
padding: 20px; </fieldset>
text-align: left; </div>
} <fieldset class="cbi-section" style="display:none">
</style> <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