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