1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
|
-- Copyright 2014 Aedan Renner <chipdankly@gmail.com
-- Copyright 2018 Florian Eckert <fe@dev.tdt.de>
-- Licensed to the public under the GNU General Public License v2.
local dsp = require "luci.dispatcher"
local uci = require "uci"
local m, mwan_interface, enabled, track_method, reliability, interval
local down, up, metric
function interfaceWarnings(overview, count, iface_max)
local warnings = ""
if count <= iface_max then
warnings = string.format("<strong>%s</strong><br />",
translatef("There are currently %d of %d supported interfaces configured", count, iface_max)
)
else
warnings = string.format("<strong>%s</strong><br />",
translatef("WARNING: %d interfaces are configured exceeding the maximum of %d!", count, iface_max)
)
end
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
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
local device = uci:get("network", iface, "ifname")
if device ~= nil then
overview[iface]["device"] = device
end
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 and dump.route 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
local trackingNumber = uci:get("mwan3", iface, "track_ip")
overview[iface]["tracking"] = 0
if trackingNumber and #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
)
-- calculate iface_max usage from firewall mmx_mask
function bit(p)
return 2 ^ (p - 1)
end
function hasbit(x, p)
return x % (p + p) >= p
end
function setbit(x, p)
return hasbit(x, p) and x or x + p
end
local uci = require("uci").cursor(nil, "/var/state")
local mmx_mask = uci:get("mwan3", "globals", "mmx_mask") or "0x3F00"
local number = tonumber(mmx_mask, 16)
local bits = 0
local iface_max = 0
for i=1,16 do
if hasbit(number, bit(i)) then
bits = bits + 1
iface_max = setbit( iface_max, bit(bits))
end
end
-- subtract blackhole, unreachable and default table from iface_max
iface_max = iface_max - 3
return overview, count, iface_max
end
m = Map("mwan3", translate("MWAN - Interfaces"),
interfaceWarnings(configCheck()))
mwan_interface = m:section(TypedSection, "interface", nil,
translate("MWAN supports up to 252 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<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)
m.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 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)
local tracked = self.map:get(s, "track_ip")
if tracked then
return self.map:get(s, "track_method") or "ping"
else
return "—"
end
end
reliability = mwan_interface:option(DummyValue, "reliability", translate("Tracking reliability"))
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 "1"
else
return "—"
end
end
interval = mwan_interface:option(DummyValue, "interval", translate("Ping interval"))
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 "5s"
end
else
return "—"
end
end
down = mwan_interface:option(DummyValue, "down", translate("Interface down"))
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 "3"
else
return "—"
end
end
up = mwan_interface:option(DummyValue, "up", translate("Interface up"))
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 "3"
else
return "—"
end
end
metric = mwan_interface:option(DummyValue, "metric", translate("Metric"))
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 "—"
end
end
return m
|