Merge pull request #1071 from TDT-GmbH/add-force-link-option
[project/luci.git] / applications / luci-app-mwan3 / luasrc / model / cbi / mwan / interface.lua
1 -- ------ extra functions ------ --
2
3 function interfaceCheck() -- find issues with too many interfaces, reliability and metric
4         uci.cursor():foreach("mwan3", "interface",
5                 function (section)
6                         local interfaceName = section[".name"]
7                         interfaceNumber = interfaceNumber+1 -- count number of mwan interfaces configured
8                         -- create list of metrics for none and duplicate checking
9                         local metricValue = ut.trim(sys.exec("uci -p /var/state get network." .. interfaceName .. ".metric"))
10                         if metricValue == "" then
11                                 errorFound = 1
12                                 errorNoMetricList = errorNoMetricList .. interfaceName .. " "
13                         else
14                                 metricList = metricList .. interfaceName .. " " .. metricValue .. "\n"
15                         end
16                         -- check if any interfaces have a higher reliability requirement than tracking IPs configured
17                         local trackingNumber = tonumber(ut.trim(sys.exec("echo $(uci -p /var/state get mwan3." .. interfaceName .. ".track_ip) | wc -w")))
18                         if trackingNumber > 0 then
19                                 local reliabilityNumber = tonumber(ut.trim(sys.exec("uci -p /var/state get mwan3." .. interfaceName .. ".reliability")))
20                                 if reliabilityNumber and reliabilityNumber > trackingNumber then
21                                         errorFound = 1
22                                         errorReliabilityList = errorReliabilityList .. interfaceName .. " "
23                                 end
24                         end
25                         -- check if any interfaces are not properly configured in /etc/config/network or have no default route in main routing table
26                         if ut.trim(sys.exec("uci -p /var/state get network." .. interfaceName)) == "interface" then
27                                 local interfaceDevice = ut.trim(sys.exec("uci -p /var/state get network." .. interfaceName .. ".ifname"))
28                                 if interfaceDevice == "uci: Entry not found" or interfaceDevice == "" then
29                                         errorFound = 1
30                                         errorNetConfigList = errorNetConfigList .. interfaceName .. " "
31                                         errorRouteList = errorRouteList .. interfaceName .. " "
32                                 else
33                                         local routeCheck = ut.trim(sys.exec("route -n | awk '{if ($8 == \"" .. interfaceDevice .. "\" && $1 == \"0.0.0.0\" && $3 == \"0.0.0.0\") print $1}'"))
34                                         if routeCheck == "" then
35                                                 errorFound = 1
36                                                 errorRouteList = errorRouteList .. interfaceName .. " "
37                                         end
38                                 end
39                         else
40                                 errorFound = 1
41                                 errorNetConfigList = errorNetConfigList .. interfaceName .. " "
42                                 errorRouteList = errorRouteList .. interfaceName .. " "
43                         end
44                 end
45         )
46         -- check if any interfaces have duplicate metrics
47         local metricDuplicateNumbers = sys.exec("echo '" .. metricList .. "' | awk '{print $2}' | uniq -d")
48         if metricDuplicateNumbers ~= "" then
49                 errorFound = 1
50                 local metricDuplicates = ""
51                 for line in metricDuplicateNumbers:gmatch("[^\r\n]+") do
52                         metricDuplicates = sys.exec("echo '" .. metricList .. "' | grep '" .. line .. "' | awk '{print $1}'")
53                         errorDuplicateMetricList = errorDuplicateMetricList .. metricDuplicates
54                 end
55                 errorDuplicateMetricList = sys.exec("echo '" .. errorDuplicateMetricList .. "' | tr '\n' ' '")
56         end
57 end
58
59 function interfaceWarnings() -- display status and warning messages at the top of the page
60         local warnings = ""
61         if interfaceNumber <= 250 then
62                 warnings = "<strong>There are currently " .. interfaceNumber .. " of 250 supported interfaces configured</strong>"
63         else
64                 warnings = "<font color=\"ff0000\"><strong>WARNING: " .. interfaceNumber .. " interfaces are configured exceeding the maximum of 250!</strong></font>"
65         end
66         if errorReliabilityList ~= " " then
67                 warnings = warnings .. "<br /><br /><font color=\"ff0000\"><strong>WARNING: some interfaces have a higher reliability requirement than there are tracking IP addresses!</strong></font>"
68         end
69         if errorRouteList ~= " " then
70                 warnings = warnings .. "<br /><br /><font color=\"ff0000\"><strong>WARNING: some interfaces have no default route in the main routing table!</strong></font>"
71         end
72         if errorNetConfigList ~= " " then
73                 warnings = warnings .. "<br /><br /><font color=\"ff0000\"><strong>WARNING: some interfaces are configured incorrectly or not at all in /etc/config/network!</strong></font>"
74         end
75         if errorNoMetricList ~= " " then
76                 warnings = warnings .. "<br /><br /><font color=\"ff0000\"><strong>WARNING: some interfaces have no metric configured in /etc/config/network!</strong></font>"
77         end
78         if errorDuplicateMetricList ~= " " then
79                 warnings = warnings .. "<br /><br /><font color=\"ff0000\"><strong>WARNING: some interfaces have duplicate metrics configured in /etc/config/network!</strong></font>"
80         end
81         return warnings
82 end
83
84 -- ------ interface configuration ------ --
85
86 dsp = require "luci.dispatcher"
87 sys = require "luci.sys"
88 ut = require "luci.util"
89
90 interfaceNumber = 0
91 metricList = ""
92 errorFound = 0
93 errorDuplicateMetricList = " "
94 errorNetConfigList = " "
95 errorNoMetricList = " "
96 errorReliabilityList = " "
97 errorRouteList = " "
98 interfaceCheck()
99
100
101 m5 = Map("mwan3", translate("MWAN Interface Configuration"),
102         translate(interfaceWarnings()))
103         m5:append(Template("mwan/config_css"))
104
105
106 mwan_interface = m5:section(TypedSection, "interface", translate("Interfaces"),
107         translate("MWAN supports up to 250 physical and/or logical interfaces<br />" ..
108         "MWAN requires that all interfaces have a unique metric configured in /etc/config/network<br />" ..
109         "Names must match the interface name found in /etc/config/network (see advanced tab)<br />" ..
110         "Names may contain characters A-Z, a-z, 0-9, _ and no spaces<br />" ..
111         "Interfaces may not share the same name as configured members, policies or rules"))
112         mwan_interface.addremove = true
113         mwan_interface.dynamic = false
114         mwan_interface.sectionhead = "Interface"
115         mwan_interface.sortable = true
116         mwan_interface.template = "cbi/tblsection"
117         mwan_interface.extedit = dsp.build_url("admin", "network", "mwan", "configuration", "interface", "%s")
118         function mwan_interface.create(self, section)
119                 TypedSection.create(self, section)
120                 m5.uci:save("mwan3")
121                 luci.http.redirect(dsp.build_url("admin", "network", "mwan", "configuration", "interface", section))
122         end
123
124
125 enabled = mwan_interface:option(DummyValue, "enabled", translate("Enabled"))
126         enabled.rawhtml = true
127         function enabled.cfgvalue(self, s)
128                 if self.map:get(s, "enabled") == "1" then
129                         return "Yes"
130                 else
131                         return "No"
132                 end
133         end
134
135 track_ip = mwan_interface:option(DummyValue, "track_ip", translate("Tracking IP"))
136         track_ip.rawhtml = true
137         function track_ip.cfgvalue(self, s)
138                 tracked = self.map:get(s, "track_ip")
139                 if tracked then
140                         local ipList = ""
141                         for k,v in pairs(tracked) do
142                                 ipList = ipList .. v .. "<br />"
143                         end
144                         return ipList
145                 else
146                         return "&#8212;"
147                 end
148         end
149
150 reliability = mwan_interface:option(DummyValue, "reliability", translate("Tracking reliability"))
151         reliability.rawhtml = true
152         function reliability.cfgvalue(self, s)
153                 if tracked then
154                         return self.map:get(s, "reliability") or "&#8212;"
155                 else
156                         return "&#8212;"
157                 end
158         end
159
160 count = mwan_interface:option(DummyValue, "count", translate("Ping count"))
161         count.rawhtml = true
162         function count.cfgvalue(self, s)
163                 if tracked then
164                         return self.map:get(s, "count") or "&#8212;"
165                 else
166                         return "&#8212;"
167                 end
168         end
169
170 timeout = mwan_interface:option(DummyValue, "timeout", translate("Ping timeout"))
171         timeout.rawhtml = true
172         function timeout.cfgvalue(self, s)
173                 if tracked then
174                         local timeoutValue = self.map:get(s, "timeout")
175                         if timeoutValue then
176                                 return timeoutValue .. "s"
177                         else
178                                 return "&#8212;"
179                         end
180                 else
181                         return "&#8212;"
182                 end
183         end
184
185 interval = mwan_interface:option(DummyValue, "interval", translate("Ping interval"))
186         interval.rawhtml = true
187         function interval.cfgvalue(self, s)
188                 if tracked then
189                         local intervalValue = self.map:get(s, "interval")
190                         if intervalValue then
191                                 return intervalValue .. "s"
192                         else
193                                 return "&#8212;"
194                         end
195                 else
196                         return "&#8212;"
197                 end
198         end
199
200 down = mwan_interface:option(DummyValue, "down", translate("Interface down"))
201         down.rawhtml = true
202         function down.cfgvalue(self, s)
203                 if tracked then
204                         return self.map:get(s, "down") or "&#8212;"
205                 else
206                         return "&#8212;"
207                 end
208         end
209
210 up = mwan_interface:option(DummyValue, "up", translate("Interface up"))
211         up.rawhtml = true
212         function up.cfgvalue(self, s)
213                 if tracked then
214                         return self.map:get(s, "up") or "&#8212;"
215                 else
216                         return "&#8212;"
217                 end
218         end
219
220 metric = mwan_interface:option(DummyValue, "metric", translate("Metric"))
221         metric.rawhtml = true
222         function metric.cfgvalue(self, s)
223                 local metricValue = sys.exec("uci -p /var/state get network." .. s .. ".metric")
224                 if metricValue ~= "" then
225                         return metricValue
226                 else
227                         return "&#8212;"
228                 end
229         end
230
231 errors = mwan_interface:option(DummyValue, "errors", translate("Errors"))
232         errors.rawhtml = true
233         function errors.cfgvalue(self, s)
234                 if errorFound == 1 then
235                         local mouseOver, lineBreak = "", ""
236                         if string.find(errorReliabilityList, " " .. s .. " ") then
237                                 mouseOver = "Higher reliability requirement than there are tracking IP addresses"
238                                 lineBreak = "&#10;&#10;"
239                         end
240                         if string.find(errorRouteList, " " .. s .. " ") then
241                                 mouseOver = mouseOver .. lineBreak .. "No default route in the main routing table"
242                                 lineBreak = "&#10;&#10;"
243                         end
244                         if string.find(errorNetConfigList, " " .. s .. " ") then
245                                 mouseOver = mouseOver .. lineBreak .. "Configured incorrectly or not at all in /etc/config/network"
246                                 lineBreak = "&#10;&#10;"
247                         end
248                         if string.find(errorNoMetricList, " " .. s .. " ") then
249                                 mouseOver = mouseOver .. lineBreak .. "No metric configured in /etc/config/network"
250                                 lineBreak = "&#10;&#10;"
251                         end
252                         if string.find(errorDuplicateMetricList, " " .. s .. " ") then
253                                 mouseOver = mouseOver .. lineBreak .. "Duplicate metric configured in /etc/config/network"
254                         end
255                         if mouseOver == "" then
256                                 return ""
257                         else
258                                 return "<span title=\"" .. mouseOver .. "\"><img src=\"/luci-static/resources/cbi/reset.gif\" alt=\"error\"></img></span>"
259                         end
260                 else
261                         return ""
262                 end
263         end
264
265
266 return m5