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"},
template("mwan/status_troubleshooting"))
entry({"admin", "status", "mwan", "interface_status"},
call("interfaceStatus"))
call("mwan_Status"))
entry({"admin", "status", "mwan", "detailed_status"},
call("detailedStatus"))
entry({"admin", "status", "mwan", "diagnostics_display"},
@ -56,83 +56,31 @@ function index()
_("Notification"), 50).leaf = true
end
function getInterfaceStatus(ruleNumber, interfaceName)
if ut.trim(sys.exec("uci -q -p /var/state get mwan3." .. interfaceName .. ".enabled")) == "1" then
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
function mwan_Status()
local status = ut.ubus("mwan3", "status", {})
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
function detailedStatus()
local mArray = {}
-- detailed mwan status
local detailStatusInfo = ut.trim(sys.exec("/usr/sbin/mwan3 status"))
if detailStatusInfo ~= "" then
mArray.mwandetail = { detailStatusInfo }
local statusInfo = ut.trim(sys.exec("/usr/sbin/mwan3 status"))
luci.http.prepare_content("text/plain")
if statusInfo ~= "" then
luci.http.write(statusInfo)
else
luci.http.write("Unable to get status information")
end
luci.http.prepare_content("application/json")
luci.http.write_json(mArray)
end
function diagnosticsData(interface, tool, task)
function getInterfaceNumber()
function diagnosticsData(interface, task)
function getInterfaceNumber(interface)
local number = 0
local interfaceNumber
uci.cursor():foreach("mwan3", "interface",
function (section)
number = number+1
@ -141,184 +89,213 @@ function diagnosticsData(interface, tool, task)
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
local mArray = {}
local results = ""
if tool == "service" then
os.execute("/usr/sbin/mwan3 " .. task)
if task == "restart" then
results = "MWAN3 restarted"
elseif task == "stop" then
results = "MWAN3 stopped"
local number = getInterfaceNumber(interface)
local uci = uci.cursor(nil, "/var/state")
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
results = "MWAN3 started"
luci.http.write("Unknown task")
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
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
if results ~= "" then
results = ut.trim(results)
mArray.diagnostics = { results }
end
luci.http.prepare_content("application/json")
luci.http.write_json(mArray)
end
function troubleshootingData()
local ver = require "luci.version"
local dash = "-------------------------------------------------"
local mArray = {}
luci.http.prepare_content("text/plain")
-- software versions
local wrtRelease = ut.trim(ver.distversion)
if wrtRelease ~= "" then
wrtRelease = "OpenWrt - " .. wrtRelease
else
wrtRelease = "OpenWrt - unknown"
end
local luciRelease = ut.trim(ver.luciversion)
if luciRelease ~= "" then
luciRelease = "\nLuCI - " .. luciRelease
else
luciRelease = "\nLuCI - unknown"
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 }
luci.http.write("\n")
luci.http.write("\n")
luci.http.write("Software-Version")
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
luci.http.write("OpenWrt - unknown")
luci.http.write("\n")
end
-- mwan config
local mwanConfig = ut.trim(sys.exec("cat /etc/config/mwan3"))
if mwanConfig == "" then
mwanConfig = "No data found"
end
mArray.mwanconfig = { mwanConfig }
if ver.luciversion then
luci.http.write(string.format("LuCI - %s", ver.luciversion))
luci.http.write("\n")
else
luci.http.write("LuCI - unknown")
luci.http.write("\n")
end
-- network config
local networkConfig = ut.trim(sys.exec("cat /etc/config/network | sed -e 's/.*username.*/ USERNAME HIDDEN/' -e 's/.*password.*/ PASSWORD HIDDEN/'"))
if networkConfig == "" then
networkConfig = "No data found"
end
mArray.netconfig = { networkConfig }
luci.http.write("\n")
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
luci.http.write("No data found")
luci.http.write("\n")
end
-- 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 }
luci.http.write("\n")
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
luci.http.write("No data found")
luci.http.write("\n")
end
-- ifconfig
local ifconfig = ut.trim(sys.exec("ifconfig"))
if ifconfig == "" then
ifconfig = "No data found"
end
mArray.ifconfig = { ifconfig }
luci.http.write("\n")
luci.http.write("\n")
local output = ut.trim(sys.exec("ip rule show"))
luci.http.write("Output of \"ip rule 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
luci.http.write("No data found")
luci.http.write("\n")
end
-- route -n
local routeShow = ut.trim(sys.exec("route -n"))
if routeShow == "" then
routeShow = "No data found"
luci.http.write("\n")
luci.http.write("\n")
luci.http.write("Output of \"ip route list table 1-250\"")
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
mArray.routeshow = { routeShow }
end
-- 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
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)
luci.http.write("\n")
luci.http.write("\n")
local output = ut.trim(sys.exec("iptables -L -t mangle -v -n"))
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

View file

@ -14,12 +14,14 @@ $Id$
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",
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.default = "none"
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 = ""
if interfaceNumber <= 250 then
warnings = "<strong>" .. translatef("There are currently %d of 250 supported interfaces configured", interfaceNumber) .. "</strong>"
if count <= 250 then
warnings = string.format("<strong>%s</strong></br>",
translatef("There are currently %d of 250 supported interfaces configured", count)
)
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
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>"
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>"
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>"
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>"
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>"
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
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
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
return warnings
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"
sys = require "luci.sys"
ut = require "luci.util"
local device = uci:get("network", iface, "ifname")
if device ~= nil then
overview[iface]["device"] = device
end
interfaceNumber = 0
metricList = ""
errorFound = 0
errorDuplicateMetricList = " "
errorNetConfigList = " "
errorNoMetricList = " "
errorReliabilityList = " "
errorRouteList = " "
interfaceCheck()
local metric = uci:get("network", iface, "metric")
if metric ~= nil then
overview[iface]["metric"] = metric
overview[iface]["duplicate_metric"] = false
for _, m in ipairs(duplicate_metric) do
if m == metric then
overview[iface]["duplicate_metric"] = true
end
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"),
interfaceWarnings())
m5:append(Template("mwan/config_css"))
local trackingNumber = uci:get("mwan3", iface, "track_ip")
overview[iface]["tracking"] = 0
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 />" ..
"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 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"))
mwan_interface.addremove = true
mwan_interface.dynamic = false
mwan_interface.sectionhead = translate("Interface")
mwan_interface.sortable = false
mwan_interface.template = "cbi/tblsection"
mwan_interface.extedit = dsp.build_url("admin", "network", "mwan", "interface", "%s")
function mwan_interface.create(self, section)
TypedSection.create(self, section)
m5.uci:save("mwan3")
luci.http.redirect(dsp.build_url("admin", "network", "mwan", "interface", section))
end
mwan_interface.addremove = true
mwan_interface.dynamic = false
mwan_interface.sectionhead = translate("Interface")
mwan_interface.sortable = false
mwan_interface.template = "cbi/tblsection"
mwan_interface.extedit = dsp.build_url("admin", "network", "mwan", "interface", "%s")
function mwan_interface.create(self, section)
TypedSection.create(self, section)
m5.uci:save("mwan3")
luci.http.redirect(dsp.build_url("admin", "network", "mwan", "interface", section))
end
enabled = mwan_interface:option(DummyValue, "enabled", translate("Enabled"))
enabled.rawhtml = true
function enabled.cfgvalue(self, s)
if self.map:get(s, "enabled") == "1" then
return "Yes"
else
return "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
enabled.rawhtml = true
function enabled.cfgvalue(self, s)
if self.map:get(s, "enabled") == "1" then
return translate("Yes")
else
return translate("No")
end
end
track_method = mwan_interface:option(DummyValue, "track_method", translate("Tracking method"))
track_method.rawhtml = true
function track_method.cfgvalue(self, s)
if tracked then
return self.map:get(s, "track_method") or "&#8212;"
else
return "&#8212;"
end
track_method.rawhtml = true
function track_method.cfgvalue(self, s)
local tracked = self.map:get(s, "track_ip")
if tracked then
return self.map:get(s, "track_method") or "&#8212;"
else
return "&#8212;"
end
end
reliability = mwan_interface:option(DummyValue, "reliability", translate("Tracking reliability"))
reliability.rawhtml = true
function reliability.cfgvalue(self, s)
if tracked then
return self.map:get(s, "reliability") or "&#8212;"
else
return "&#8212;"
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
reliability.rawhtml = true
function reliability.cfgvalue(self, s)
local tracked = self.map:get(s, "track_ip")
if tracked then
return self.map:get(s, "reliability") or "&#8212;"
else
return "&#8212;"
end
end
interval = mwan_interface:option(DummyValue, "interval", translate("Ping interval"))
interval.rawhtml = true
function interval.cfgvalue(self, s)
if tracked then
local intervalValue = self.map:get(s, "interval")
if intervalValue then
return intervalValue .. "s"
else
return "&#8212;"
end
interval.rawhtml = true
function interval.cfgvalue(self, s)
local tracked = self.map:get(s, "track_ip")
if tracked then
local intervalValue = self.map:get(s, "interval")
if intervalValue then
return intervalValue .. "s"
else
return "&#8212;"
end
else
return "&#8212;"
end
end
down = mwan_interface:option(DummyValue, "down", translate("Interface down"))
down.rawhtml = true
function down.cfgvalue(self, s)
if tracked then
return self.map:get(s, "down") or "&#8212;"
else
return "&#8212;"
end
down.rawhtml = true
function down.cfgvalue(self, s)
local tracked = self.map:get(s, "track_ip")
if tracked then
return self.map:get(s, "down") or "&#8212;"
else
return "&#8212;"
end
end
up = mwan_interface:option(DummyValue, "up", translate("Interface up"))
up.rawhtml = true
function up.cfgvalue(self, s)
if tracked then
return self.map:get(s, "up") or "&#8212;"
else
return "&#8212;"
end
up.rawhtml = true
function up.cfgvalue(self, s)
local tracked = self.map:get(s, "track_ip")
if tracked then
return self.map:get(s, "up") or "&#8212;"
else
return "&#8212;"
end
end
metric = mwan_interface:option(DummyValue, "metric", translate("Metric"))
metric.rawhtml = true
function metric.cfgvalue(self, s)
local metricValue = sys.exec("uci -p /var/state get network." .. s .. ".metric")
if metricValue ~= "" then
return metricValue
else
return "&#8212;"
end
metric.rawhtml = true
function metric.cfgvalue(self, s)
local uci = uci.cursor(nil, "/var/state")
local metric = uci:get("network", s, "metric")
if metric then
return metric
else
return "&#8212;"
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
end
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"
sys = require "luci.sys"
ut = require "luci.util"
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]),
interfaceWarnings())
m5 = Map("mwan3", translatef("MWAN Interface Configuration - %s", arg[1]))
m5.redirect = dsp.build_url("admin", "network", "mwan", "interface")
mwan_interface = m5:section(NamedSection, arg[1], "interface", "")
mwan_interface.addremove = false
mwan_interface.dynamic = false
mwan_interface.addremove = false
mwan_interface.dynamic = false
enabled = mwan_interface:option(ListValue, "enabled", translate("Enabled"))
enabled.default = "1"
enabled:value("1", translate("Yes"))
enabled:value("0", translate("No"))
enabled.default = "1"
enabled:value("1", translate("Yes"))
enabled:value("0", translate("No"))
initial_state = mwan_interface:option(ListValue, "initial_state", translate("Initial state"),
translate("Expect interface state on up event"))
initial_state.default = "online"
initial_state:value("online", translate("Online"))
initial_state:value("offline", translate("Offline"))
initial_state.default = "online"
initial_state:value("online", translate("Online"))
initial_state:value("offline", translate("Offline"))
family = mwan_interface:option(ListValue, "family", translate("Internet Protocol"))
family.default = "ipv4"
family:value("ipv4", translate("IPv4"))
family:value("ipv6", translate("IPv6"))
family.default = "ipv4"
family:value("ipv4", translate("IPv4"))
family:value("ipv6", translate("IPv6"))
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"))
track_ip.datatype = "host"
track_ip.datatype = "host"
track_method = mwan_interface:option(ListValue, "track_method", translate("Tracking method"))
track_method.default = "ping"
track_method:value("ping")
track_method:value("arping")
track_method:value("httping")
track_method.default = "ping"
track_method:value("ping")
track_method:value("arping")
track_method:value("httping")
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"))
reliability.datatype = "range(1, 100)"
reliability.default = "1"
reliability.datatype = "range(1, 100)"
reliability.default = "1"
count = mwan_interface:option(ListValue, "count", translate("Ping count"))
count.default = "1"
count:value("1")
count:value("2")
count:value("3")
count:value("4")
count:value("5")
count.default = "1"
count:value("1")
count:value("2")
count:value("3")
count:value("4")
count:value("5")
size = mwan_interface:option(Value, "size", translate("Ping size"))
size.default = "56"
size:value("8")
size:value("24")
size:value("56")
size:value("120")
size:value("248")
size:value("504")
size:value("1016")
size:value("1472")
size:value("2040")
size.datatype = "range(1, 65507)"
size.rmempty = false
size.optional = false
size.default = "56"
size:value("8")
size:value("24")
size:value("56")
size:value("120")
size:value("248")
size:value("504")
size:value("1016")
size:value("1472")
size:value("2040")
size.datatype = "range(1, 65507)"
size.rmempty = false
size.optional = false
timeout = mwan_interface:option(ListValue, "timeout", translate("Ping timeout"))
timeout.default = "2"
timeout:value("1", translatef("%d second", 1))
timeout:value("2", translatef("%d seconds", 2))
timeout:value("3", translatef("%d seconds", 3))
timeout:value("4", translatef("%d seconds", 4))
timeout:value("5", translatef("%d seconds", 5))
timeout:value("6", translatef("%d seconds", 6))
timeout:value("7", translatef("%d seconds", 7))
timeout:value("8", translatef("%d seconds", 8))
timeout:value("9", translatef("%d seconds", 9))
timeout:value("10", translatef("%d seconds", 10))
timeout.default = "2"
timeout:value("1", translatef("%d second", 1))
timeout:value("2", translatef("%d seconds", 2))
timeout:value("3", translatef("%d seconds", 3))
timeout:value("4", translatef("%d seconds", 4))
timeout:value("5", translatef("%d seconds", 5))
timeout:value("6", translatef("%d seconds", 6))
timeout:value("7", translatef("%d seconds", 7))
timeout:value("8", translatef("%d seconds", 8))
timeout:value("9", translatef("%d seconds", 9))
timeout:value("10", translatef("%d seconds", 10))
interval = mwan_interface:option(ListValue, "interval", translate("Ping interval"))
interval.default = "5"
interval:value("1", translatef("%d second", 1))
interval:value("3", translatef("%d seconds", 3))
interval:value("5", translatef("%d seconds", 5))
interval:value("10", translatef("%d seconds", 10))
interval:value("20", translatef("%d seconds", 20))
interval:value("30", translatef("%d seconds", 30))
interval:value("60", translatef("%d minute", 1))
interval:value("300", translatef("%d minutes", 5))
interval:value("600", translatef("%d minutes", 10))
interval:value("900", translatef("%d minutes", 15))
interval:value("1800", translatef("%d minutes", 30))
interval:value("3600", translatef("%d hour", 1))
interval.default = "5"
interval:value("1", translatef("%d second", 1))
interval:value("3", translatef("%d seconds", 3))
interval:value("5", translatef("%d seconds", 5))
interval:value("10", translatef("%d seconds", 10))
interval:value("20", translatef("%d seconds", 20))
interval:value("30", translatef("%d seconds", 30))
interval:value("60", translatef("%d minute", 1))
interval:value("300", translatef("%d minutes", 5))
interval:value("600", translatef("%d minutes", 10))
interval:value("900", translatef("%d minutes", 15))
interval:value("1800", translatef("%d minutes", 30))
interval:value("3600", translatef("%d hour", 1))
failure = mwan_interface:option(Value, "failure_interval", translate("Failure interval"),
translate("Ping interval during failure detection"))
failure.default = "5"
failure:value("1", translatef("%d second", 1))
failure:value("3", translatef("%d seconds", 3))
failure:value("5", translatef("%d seconds", 5))
failure:value("10", translatef("%d seconds", 10))
failure:value("20", translatef("%d seconds", 20))
failure:value("30", translatef("%d seconds", 30))
failure:value("60", translatef("%d minute", 1))
failure:value("300", translatef("%d minutes", 5))
failure:value("600", translatef("%d minutes", 10))
failure:value("900", translatef("%d minutes", 15))
failure:value("1800", translatef("%d minutes", 30))
failure:value("3600", translatef("%d hour", 1))
failure.default = "5"
failure:value("1", translatef("%d second", 1))
failure:value("3", translatef("%d seconds", 3))
failure:value("5", translatef("%d seconds", 5))
failure:value("10", translatef("%d seconds", 10))
failure:value("20", translatef("%d seconds", 20))
failure:value("30", translatef("%d seconds", 30))
failure:value("60", translatef("%d minute", 1))
failure:value("300", translatef("%d minutes", 5))
failure:value("600", translatef("%d minutes", 10))
failure:value("900", translatef("%d minutes", 15))
failure:value("1800", translatef("%d minutes", 30))
failure:value("3600", translatef("%d hour", 1))
keep_failure = mwan_interface:option(Flag, "keep_failure_interval", translate("Keep failure interval"),
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"),
translate("Ping interval during failure recovering"))
recovery.default = "5"
recovery:value("1", translatef("%d second", 1))
recovery:value("3", translatef("%d seconds", 3))
recovery:value("5", translatef("%d seconds", 5))
recovery:value("10", translatef("%d seconds", 10))
recovery:value("20", translatef("%d seconds", 20))
recovery:value("30", translatef("%d seconds", 30))
recovery:value("60", translatef("%d minute", 1))
recovery:value("300", translatef("%d minutes", 5))
recovery:value("600", translatef("%d minutes", 10))
recovery:value("900", translatef("%d minutes", 15))
recovery:value("1800", translatef("%d minutes", 30))
recovery:value("3600", translatef("%d hour", 1))
recovery.default = "5"
recovery:value("1", translatef("%d second", 1))
recovery:value("3", translatef("%d seconds", 3))
recovery:value("5", translatef("%d seconds", 5))
recovery:value("10", translatef("%d seconds", 10))
recovery:value("20", translatef("%d seconds", 20))
recovery:value("30", translatef("%d seconds", 30))
recovery:value("60", translatef("%d minute", 1))
recovery:value("300", translatef("%d minutes", 5))
recovery:value("600", translatef("%d minutes", 10))
recovery:value("900", translatef("%d minutes", 15))
recovery:value("1800", translatef("%d minutes", 30))
recovery:value("3600", translatef("%d hour", 1))
down = mwan_interface:option(ListValue, "down", translate("Interface down"),
translate("Interface will be deemed down after this many failed ping tests"))
down.default = "3"
down:value("1")
down:value("2")
down:value("3")
down:value("4")
down:value("5")
down:value("6")
down:value("7")
down:value("8")
down:value("9")
down:value("10")
down.default = "3"
down:value("1")
down:value("2")
down:value("3")
down:value("4")
down:value("5")
down:value("6")
down:value("7")
down:value("8")
down:value("9")
down:value("10")
up = mwan_interface:option(ListValue, "up", translate("Interface up"),
translate("Downed interface will be deemed up after this many successful ping tests"))
up.default = "3"
up:value("1")
up:value("2")
up:value("3")
up:value("4")
up:value("5")
up:value("6")
up:value("7")
up:value("8")
up:value("9")
up:value("10")
up.default = "3"
up:value("1")
up:value("2")
up:value("3")
up:value("4")
up:value("5")
up:value("6")
up:value("7")
up:value("8")
up:value("9")
up:value("10")
flush = mwan_interface:option(ListValue, "flush_conntrack", translate("Flush conntrack table"),
translate("Flush global firewall conntrack table on interface events"))
flush.default = "never"
flush:value("ifup", translate("ifup"))
flush:value("ifdown", translate("ifdown"))
flush:value("never", translate("never"))
flush:value("always", translate("always"))
flush.default = "never"
flush:value("ifup", translate("ifup"))
flush:value("ifdown", translate("ifdown"))
flush:value("never", translate("never"))
flush:value("always", translate("always"))
metric = mwan_interface:option(DummyValue, "metric", translate("Metric"),
translate("This displays the metric assigned to this interface in /etc/config/network"))
metric.rawhtml = true
function metric.cfgvalue(self, s)
if errorNoMetric == 0 then
return metricValue
else
return "&#8212;"
end
metric.rawhtml = true
function metric.cfgvalue(self, s)
local uci = uci.cursor(nil, "/var/state")
local metric = uci:get("network", arg[1], "metric")
if metric then
return metric
else
return "&#8212;"
end
end
return m5

View file

@ -1,46 +1,40 @@
-- ------ member configuration ------ --
ds = require "luci.dispatcher"
dsp = require "luci.dispatcher"
m5 = Map("mwan3", translate("MWAN Member Configuration"))
m5:append(Template("mwan/config_css"))
m5 = Map("mwan3", translate("MWAN - Members"))
mwan_member = m5:section(TypedSection, "member", translate("Members"),
mwan_member = m5:section(TypedSection, "member", nil,
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 />" ..
"Members may not share the same name as configured interfaces, policies or rules"))
mwan_member.addremove = true
mwan_member.dynamic = false
mwan_member.sectionhead = translate("Member")
mwan_member.sortable = true
mwan_member.template = "cbi/tblsection"
mwan_member.extedit = ds.build_url("admin", "network", "mwan", "member", "%s")
function mwan_member.create(self, section)
TypedSection.create(self, section)
m5.uci:save("mwan3")
luci.http.redirect(ds.build_url("admin", "network", "mwan", "member", section))
end
mwan_member.addremove = true
mwan_member.dynamic = false
mwan_member.sectionhead = translate("Member")
mwan_member.sortable = true
mwan_member.template = "cbi/tblsection"
mwan_member.extedit = dsp.build_url("admin", "network", "mwan", "member", "%s")
function mwan_member.create(self, section)
TypedSection.create(self, section)
m5.uci:save("mwan3")
luci.http.redirect(dsp.build_url("admin", "network", "mwan", "member", section))
end
interface = mwan_member:option(DummyValue, "interface", translate("Interface"))
interface.rawhtml = true
function interface.cfgvalue(self, s)
return self.map:get(s, "interface") or "&#8212;"
end
interface.rawhtml = true
function interface.cfgvalue(self, s)
return self.map:get(s, "interface") or "&#8212;"
end
metric = mwan_member:option(DummyValue, "metric", translate("Metric"))
metric.rawhtml = true
function metric.cfgvalue(self, s)
return self.map:get(s, "metric") or "1"
end
metric.rawhtml = true
function metric.cfgvalue(self, s)
return self.map:get(s, "metric") or "1"
end
weight = mwan_member:option(DummyValue, "weight", translate("Weight"))
weight.rawhtml = true
function weight.cfgvalue(self, s)
return self.map:get(s, "weight") or "1"
end
weight.rawhtml = true
function weight.cfgvalue(self, s)
return self.map:get(s, "weight") or "1"
end
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"
arg[1] = arg[1] or ""
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.addremove = false
mwan_member.dynamic = false
mwan_member.addremove = false
mwan_member.dynamic = false
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"),
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"),
translate("Acceptable values: 1-1000. Defaults to 1 if not set"))
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"
weight.datatype = "range(1, 1000)"
return m5

View file

@ -1,12 +1,11 @@
-- ------ hotplug script configuration ------ --
local fs = require "nixio.fs"
local ut = require "luci.util"
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 />" ..
"The file is also preserved during sysupgrade.<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",
function (section)
policy_error[section[".name"]] = false
if string.len(section[".name"]) > 15 then
nameTooLong = 1
err_name_list = err_name_list .. section[".name"] .. " "
policy_error[section[".name"]] = true
end
end
)
return policy_error
end
function policyWarn() -- display status and warning messages at the top of the page
if nameTooLong == 1 then
return "<font color=\"ff0000\"><strong>" .. translate("WARNING: Some policies have names exceeding the maximum of 15 characters!") .. "</strong></font>"
else
return ""
function policyError(policy_error)
local warnings = ""
for i, k in pairs(policy_error) do
if policy_error[i] == true then
warnings = warnings .. string.format("<strong>%s</strong></br>",
translatef("WARNING: Policie %s has exceeding the maximum name of 15 characters", i)
)
end
end
return warnings
end
-- ------ policy configuration ------ --
m5 = Map("mwan3", translate("MWAN - Policies"),
policyError(policyCheck()))
ds = require "luci.dispatcher"
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"),
mwan_policy = m5:section(TypedSection, "policy", nil,
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 />" ..
"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 />" ..
"Policies may not share the same name as configured interfaces, members or rules"))
mwan_policy.addremove = true
mwan_policy.dynamic = false
mwan_policy.sectionhead = translate("Policy")
mwan_policy.sortable = true
mwan_policy.template = "cbi/tblsection"
mwan_policy.extedit = ds.build_url("admin", "network", "mwan", "policy", "%s")
function mwan_policy.create(self, section)
TypedSection.create(self, section)
m5.uci:save("mwan3")
luci.http.redirect(ds.build_url("admin", "network", "mwan", "policy", section))
end
mwan_policy.addremove = true
mwan_policy.dynamic = false
mwan_policy.sectionhead = translate("Policy")
mwan_policy.sortable = true
mwan_policy.template = "cbi/tblsection"
mwan_policy.extedit = dsp.build_url("admin", "network", "mwan", "policy", "%s")
function mwan_policy.create(self, section)
TypedSection.create(self, section)
m5.uci:save("mwan3")
luci.http.redirect(dsp.build_url("admin", "network", "mwan", "policy", section))
end
use_member = mwan_policy:option(DummyValue, "use_member", translate("Members assigned"))
use_member.rawhtml = true
function use_member.cfgvalue(self, s)
local memberConfig, memberList = self.map:get(s, "use_member"), ""
if memberConfig then
for k,v in pairs(memberConfig) do
memberList = memberList .. v .. "<br />"
end
return memberList
else
return "&#8212;"
use_member.rawhtml = true
function use_member.cfgvalue(self, s)
local memberConfig, memberList = self.map:get(s, "use_member"), ""
if memberConfig then
for k,v in pairs(memberConfig) do
memberList = memberList .. v .. "<br />"
end
return memberList
else
return "&#8212;"
end
end
last_resort = mwan_policy:option(DummyValue, "last_resort", translate("Last resort"))
last_resort.rawhtml = true
function last_resort.cfgvalue(self, s)
local action = self.map:get(s, "last_resort")
if action == "blackhole" then
return translate("blackhole (drop)")
elseif action == "default" then
return translate("default (use main routing table)")
else
return translate("unreachable (reject)")
end
last_resort.rawhtml = true
function last_resort.cfgvalue(self, s)
local action = self.map:get(s, "last_resort")
if action == "blackhole" then
return translate("blackhole (drop)")
elseif action == "default" then
return translate("default (use main routing table)")
else
return translate("unreachable (reject)")
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
end
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"
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.addremove = false
mwan_policy.dynamic = false
mwan_policy.addremove = false
mwan_policy.dynamic = false
use_member = mwan_policy:option(DynamicList, "use_member", translate("Member used"))
cbiAddMember(use_member)
member = mwan_policy:option(DynamicList, "use_member", translate("Member used"))
m5.uci:foreach("mwan3", "member",
function(s)
member:value(s['.name'], s['.name'])
end
)
last_resort = mwan_policy:option(ListValue, "last_resort", translate("Last resort"),
translate("When all policy members are offline use this behavior for matched traffic"))
last_resort.default = "unreachable"
last_resort:value("unreachable", translate("unreachable (reject)"))
last_resort:value("blackhole", translate("blackhole (drop)"))
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"
last_resort.default = "unreachable"
last_resort:value("unreachable", translate("unreachable (reject)"))
last_resort:value("blackhole", translate("blackhole (drop)"))
last_resort:value("default", translate("default (use main routing table)"))
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",
function (section)
local sourcePort = ut.trim(sys.exec("uci -p /var/state get mwan3." .. section[".name"] .. ".src_port"))
local destPort = ut.trim(sys.exec("uci -p /var/state get mwan3." .. section[".name"] .. ".dest_port"))
if sourcePort ~= "" or destPort ~= "" then -- ports configured
local protocol = ut.trim(sys.exec("uci -p /var/state get mwan3." .. section[".name"] .. ".proto"))
if protocol == "" or protocol == "all" then -- no or improper protocol
error_protocol_list = error_protocol_list .. section[".name"] .. " "
rule_error[section[".name"]] = false
local uci = uci.cursor(nil, "/var/state")
local sourcePort = uci:get("mwan3", section[".name"], "src_port")
local destPort = uci:get("mwan3", section[".name"], "dest_port")
if sourcePort ~= nil or destPort ~= nil then
local protocol = uci:get("mwan3", section[".name"], "proto")
if protocol == nil or protocol == "all" then
rule_error[section[".name"]] = true
end
end
end
)
return rule_error
end
function ruleWarn() -- display warning messages at the top of the page
if error_protocol_list ~= " " then
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>"
else
return ""
function ruleWarn(rule_error)
local warnings = ""
for i, k in pairs(rule_error) do
if rule_error[i] == true then
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
return warnings
end
-- ------ rule configuration ------ --
m5 = Map("mwan3", translate("MWAN - Rules"),
ruleWarn(ruleCheck())
)
dsp = require "luci.dispatcher"
sys = require "luci.sys"
ut = require "luci.util"
error_protocol_list = " "
ruleCheck()
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 />" ..
mwan_rule = m5:section(TypedSection, "rule", nil,
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 />" ..
"Rules below a matching rule are ignored<br />" ..
"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 />" ..
"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"))
mwan_rule.addremove = true
mwan_rule.anonymous = false
mwan_rule.dynamic = false
mwan_rule.sectionhead = translate("Rule")
mwan_rule.sortable = true
mwan_rule.template = "cbi/tblsection"
mwan_rule.extedit = dsp.build_url("admin", "network", "mwan", "rule", "%s")
function mwan_rule.create(self, section)
TypedSection.create(self, section)
m5.uci:save("mwan3")
luci.http.redirect(dsp.build_url("admin", "network", "mwan", "rule", section))
end
mwan_rule.addremove = true
mwan_rule.anonymous = false
mwan_rule.dynamic = false
mwan_rule.sectionhead = translate("Rule")
mwan_rule.sortable = true
mwan_rule.template = "cbi/tblsection"
mwan_rule.extedit = dsp.build_url("admin", "network", "mwan", "rule", "%s")
function mwan_rule.create(self, section)
TypedSection.create(self, section)
m5.uci:save("mwan3")
luci.http.redirect(dsp.build_url("admin", "network", "mwan", "rule", section))
end
src_ip = mwan_rule:option(DummyValue, "src_ip", translate("Source address"))
src_ip.rawhtml = true
function src_ip.cfgvalue(self, s)
return self.map:get(s, "src_ip") or "&#8212;"
end
src_ip.rawhtml = true
function src_ip.cfgvalue(self, s)
return self.map:get(s, "src_ip") or "&#8212;"
end
src_port = mwan_rule:option(DummyValue, "src_port", translate("Source port"))
src_port.rawhtml = true
function src_port.cfgvalue(self, s)
return self.map:get(s, "src_port") or "&#8212;"
end
src_port.rawhtml = true
function src_port.cfgvalue(self, s)
return self.map:get(s, "src_port") or "&#8212;"
end
dest_ip = mwan_rule:option(DummyValue, "dest_ip", translate("Destination address"))
dest_ip.rawhtml = true
function dest_ip.cfgvalue(self, s)
return self.map:get(s, "dest_ip") or "&#8212;"
end
dest_ip.rawhtml = true
function dest_ip.cfgvalue(self, s)
return self.map:get(s, "dest_ip") or "&#8212;"
end
dest_port = mwan_rule:option(DummyValue, "dest_port", translate("Destination port"))
dest_port.rawhtml = true
function dest_port.cfgvalue(self, s)
return self.map:get(s, "dest_port") or "&#8212;"
end
dest_port.rawhtml = true
function dest_port.cfgvalue(self, s)
return self.map:get(s, "dest_port") or "&#8212;"
end
proto = mwan_rule:option(DummyValue, "proto", translate("Protocol"))
proto.rawhtml = true
function proto.cfgvalue(self, s)
return self.map:get(s, "proto") or "all"
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
proto.rawhtml = true
function proto.cfgvalue(self, s)
return self.map:get(s, "proto") or "all"
end
use_policy = mwan_rule:option(DummyValue, "use_policy", translate("Policy assigned"))
use_policy.rawhtml = true
function use_policy.cfgvalue(self, s)
return self.map:get(s, "use_policy") or "&#8212;"
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
use_policy.rawhtml = true
function use_policy.cfgvalue(self, s)
return self.map:get(s, "use_policy") or "&#8212;"
end
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"
sys = require "luci.sys"
ut = require "luci.util"
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.addremove = false
mwan_rule.dynamic = false
mwan_rule.addremove = false
mwan_rule.dynamic = false
src_ip = mwan_rule:option(Value, "src_ip", translate("Source address"),
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"),
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"),
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"),
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"),
translate("View the contents of /etc/protocols for protocol descriptions"))
proto.default = "all"
proto.rmempty = false
proto:value("all")
proto:value("ip")
proto:value("tcp")
proto:value("udp")
proto:value("icmp")
proto:value("esp")
cbiAddProtocol(proto)
translate("View the content of /etc/protocols for protocol description"))
proto.default = "all"
proto.rmempty = false
proto:value("all")
proto:value("tcp")
proto:value("udp")
proto:value("icmp")
proto:value("esp")
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"))
sticky.default = "0"
sticky:value("1", translate("Yes"))
sticky:value("0", translate("No"))
sticky.default = "0"
sticky:value("1", translate("Yes"))
sticky:value("0", translate("No"))
timeout = mwan_rule:option(Value, "timeout", translate("Sticky timeout"),
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"),
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"))
cbiAddPolicy(use_policy)
use_policy:value("unreachable", translate("unreachable (reject)"))
use_policy:value("blackhole", translate("blackhole (drop)"))
use_policy:value("default", translate("default (use main routing table)"))
-- ------ currently configured policies ------ --
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"
policy = mwan_rule:option(Value, "use_policy", translate("Policy assigned"))
m5.uci:foreach("mwan3", "policy",
function(s)
policy:value(s['.name'], s['.name'])
end
)
policy:value("unreachable", translate("unreachable (reject)"))
policy:value("blackhole", translate("blackhole (drop)"))
policy:value("default", translate("default (use main routing table)"))
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[
XHR.poll(5, '<%=luci.dispatcher.build_url("admin", "status", "mwan", "interface_status")%>', null,
function(x, mArray)
XHR.poll(5, '<%=luci.dispatcher.build_url("admin", "status", "mwan", "interface_status")%>', null,
function(x, status)
{
var status = document.getElementById('mwan_status_text');
if (mArray.wans)
var statusDiv = document.getElementById('mwan_status_text');
if (status.interfaces)
{
var temp = '';
for ( var i = 0; i < mArray.wans.length; i++ )
var statusview = '';
for ( var iface in status.interfaces)
{
var stat = '';
var cssc = '';
switch (mArray.wans[i].status)
var state = '';
var css = '';
switch (status.interfaces[iface].status)
{
case 'online':
stat = '<%:Online (tracking active)%>';
cssc = 'wanon';
state = '<%:Online (tracking active)%>';
css = 'wanon';
break;
case 'notMonitored':
stat = '<%:Online (tracking off)%>';
cssc = 'wanon';
state = '<%:Online (tracking off)%>';
css = 'wanon';
break;
case 'offline':
stat = '<%:Offline%>';
cssc = 'wanoff';
state = '<%:Offline%>';
css = 'wanoff';
break;
case 'notEnabled':
stat = '<%:Disabled%>';
cssc = 'wanoff';
default:
state = '<%:Disabled%>';
css = 'wanoff';
break;
}
temp += String.format(
'<span class="%s"><strong>%s (<a href="%q">%s</a>)</strong><br />%s</span>',
cssc, mArray.wans[i].name, mArray.wans[i].link, mArray.wans[i].ifname, stat
statusview += String.format(
'<span class="%s"><strong>%s</strong><br />%s</span>',
css,
iface,
state
);
}
status.innerHTML = temp;
statusDiv.innerHTML = statusview;
}
else
{
status.innerHTML = '<strong><%:No MWAN interfaces found%></strong>';
statusDiv.innerHTML = '<strong><%:No MWAN interfaces found%></strong>';
}
}
);

View file

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

View file

@ -1,8 +1,8 @@
<%+header%>
<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/detail")%>"><%:Detailed 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")%>"><%:Detail%></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>
</ul>
@ -10,10 +10,11 @@
<%
local uci = require "luci.model.uci"
interfaceNames = ""
local iface = {}
uci.cursor():foreach("mwan3", "interface",
function (section)
interfaceNames = interfaceNames .. section[".name"] .. " "
table.insert(iface, section[".name"])
end
)
%>
@ -22,92 +23,64 @@
<script type="text/javascript">//<![CDATA[
var stxhr = new XHR();
function update_status(tool, task, task_name)
function update_status(iface, task)
{
var iface = document.getElementById('mwaniface').value;
var output = document.getElementById('diag_output');
var legend = document.getElementById('diag-rc-legend');
var output = document.getElementById('diag-rc-output');
if (tool == "service")
{
output.innerHTML =
'<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.innerHTML =
'<img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align: middle;" />' +
"<%:Waiting for command to complete...%>"
;
output.parentNode.style.display = 'block';
output.style.display = 'inline';
stxhr.get('<%=luci.dispatcher.build_url("admin", "status", "mwan")%>/diagnostics_display' + '/' + iface + '/' + tool + '/' + task, null,
function(x, mArray)
stxhr.post('<%=url('admin/status/mwan')%>/diagnostics_display' + '/' + iface + '/' + task, { token: '<%=token%>' },
function(x)
{
if (mArray.diagnostics)
{
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>';
}
legend.style.display = 'none';
output.innerHTML = String.format('<pre>%h</pre>', x.responseText);
}
);
}
//]]></script>
<div id="mwan_diagnostics" class="cbi-map">
<fieldset id="diag_select" class="cbi-section">
<legend><%:MWAN Interface Diagnostics%></legend>
<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>
<form method="post" action="<%=url('admin/network/diagnostics')%>">
<div class="cbi-map">
<h2 name="content"><%:MWAN Status - Diagnostics%></h2>
<style type="text/css">
#mwaniface {
float: left;
margin: 8px 20px 0px 0px;
}
#buttoncss {
display: table;
float: left;
text-align: left;
}
.cbi-button {
margin: 8px 20px 0px 0px;
min-width: 153px;
}
#diag_output_css {
padding: 20px;
text-align: left;
}
</style>
<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>
</div>
<div style="width:30%; float:left">
<label class="cbi-value-title"><%:Task%></label>
<select name="task" style="width:auto">
<option value="ping_gateway"><%:Ping default gateway%></option>
<option value="ping_trackips"><%:Ping tracking IP%></option>
<option value="check_rules"><%:Check IP rules%></option>
<option value="check_routes"><%:Check routing table%></option>
<option value="hotplug_ifup"><%:Hotplug ifup%>"</option>
<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%>

View file

@ -1,8 +1,8 @@
<%+header%>
<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-disabled"><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/overview")%>"><%:Interface%></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/troubleshooting")%>"><%:Troubleshooting%></a></li>
</ul>
@ -10,70 +10,57 @@
<script type="text/javascript" src="<%=resource%>/cbi.js"></script>
<script type="text/javascript">//<![CDATA[
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');
if (mArray.wans)
if (status.interfaces)
{
var interfaceStatus = '';
for ( var i = 0; i < mArray.wans.length; i++ )
var statusview = '';
for ( var iface in status.interfaces)
{
var status = '';
var state = '';
var css = '';
switch (mArray.wans[i].status)
switch (status.interfaces[iface].status)
{
case 'online':
status = '<%:Online (tracking active)%>';
state = '<%:Online (tracking active)%>';
css = 'wanon';
break;
case 'notMonitored':
status = '<%:Online (tracking off)%>';
state = '<%:Online (tracking off)%>';
css = 'wanon';
break;
case 'offline':
status = '<%:Offline%>';
state = '<%:Offline%>';
css = 'wanoff';
break;
case 'notEnabled':
status = '<%:Disabled%>';
default:
state = '<%:Disabled%>';
css = 'wanoff';
break;
}
interfaceStatus += String.format(
'<span class="%s"><strong>%s (<a href="%q">%s</a>)</strong><br />%s</span>',
css, mArray.wans[i].name, mArray.wans[i].link, mArray.wans[i].ifname, status
statusview += String.format(
'<span class="%s"><strong>%s</strong><br />%s</span>',
css,
iface,
state
);
}
statusDiv.innerHTML = interfaceStatus;
statusDiv.innerHTML = statusview;
}
else
{
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>
<div id="mwan_interface_status">
<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>
</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>
<style type="text/css">

View file

@ -1,8 +1,8 @@
<%+header%>
<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/detail")%>"><%:Detailed 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")%>"><%: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"><a href="<%=luci.dispatcher.build_url("admin/status/mwan/troubleshooting")%>"><%:Troubleshooting%></a></li>
</ul>
@ -10,52 +10,24 @@
<script type="text/javascript" src="<%=resource%>/cbi.js"></script>
<script type="text/javascript">//<![CDATA[
XHR.poll(15, '<%=luci.dispatcher.build_url("admin", "status", "mwan", "troubleshooting_display")%>', null,
function(x, mArray)
function(x)
{
var tshoot = document.getElementById('troubleshoot_text');
if (mArray.versions)
{
var versions = '<span class="description">Software versions : </span><br /><br />';
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>';
}
var legend = document.getElementById('diag-rc-legend');
var output = document.getElementById('diag-rc-output');
legend.style.display = 'none';
output.innerHTML = String.format('<pre>%h</pre>', x.responseText);
}
);
//]]></script>
<div id="troubleshoot">
<div class="cbi-map">
<h2 name="content"><%:MWAN Status - Troubleshooting%></h2>
<fieldset class="cbi-section">
<legend><%:Troubleshooting Data%></legend>
<div id="troubleshoot_text"><img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align:middle" /><%:Collecting data...%></div>
<legend id="diag-rc-legend"><%:Collecting data...%></legend>
<span id="diag-rc-output">
<img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align: middle;" />
</span>
</fieldset>
</div>
<style type="text/css">
#troubleshoot_text {
padding: 20px;
text-align: left;
}
.description {
background-color: rgb(78, 186, 241);
}
</style>
<%+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