libs/core: extend network model, only allow one zone per network
[project/luci.git] / libs / core / luasrc / model / network.lua
1 --[[
2 LuCI - Network model
3
4 Copyright 2009 Jo-Philipp Wich <xm@subsignal.org>
5
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17
18 ]]--
19
20 local type, pairs, ipairs, table, i18n
21 = type, pairs, ipairs, table, luci.i18n
22
23 local lmo = require "lmo"
24 local nxo = require "nixio"
25 local nfs = require "nixio.fs"
26 local iwi = require "iwinfo"
27 local ipc = require "luci.ip"
28 local utl = require "luci.util"
29 local uct = require "luci.model.uci.bind"
30
31 module "luci.model.network"
32
33
34 local ub = uct.bind("network")
35 local ifs, brs
36
37 function init(cursor)
38 if cursor then
39 cursor:unload("network")
40 cursor:load("network")
41 ub:init(cursor)
42
43 ifs = { }
44 brs = { }
45
46 -- read interface information
47 local n, i
48 for n, i in ipairs(nxo.getifaddrs()) do
49 local name = i.name:match("[^:]+")
50
51 if not _M:ignore_interface(name) then
52 ifs[name] = ifs[name] or {
53 idx = i.ifindex or n,
54 name = name,
55 rawname = i.name,
56 flags = { },
57 ipaddrs = { },
58 ip6addrs = { }
59 }
60
61 if i.family == "packet" then
62 ifs[name].flags = i.flags
63 ifs[name].stats = i.data
64 ifs[name].macaddr = i.addr
65 elseif i.family == "inet" then
66 ifs[name].ipaddrs[#ifs[name].ipaddrs+1] = ipc.IPv4(i.addr, i.netmask)
67 elseif i.family == "inet6" then
68 ifs[name].ip6addrs[#ifs[name].ip6addrs+1] = ipc.IPv6(i.addr, i.netmask)
69 end
70 end
71 end
72
73 -- read bridge informaton
74 local b, l
75 for l in utl.execi("brctl show") do
76 if not l:match("STP") then
77 local r = utl.split(l, "%s+", nil, true)
78 if #r == 4 then
79 b = {
80 name = r[1],
81 id = r[2],
82 stp = r[3] == "yes",
83 ifnames = { ifs[r[4]] }
84 }
85 if b.ifnames[1] then
86 b.ifnames[1].bridge = b
87 end
88 brs[r[1]] = b
89 elseif b then
90 b.ifnames[#b.ifnames+1] = ifs[r[2]]
91 b.ifnames[#b.ifnames].bridge = b
92 end
93 end
94 end
95 end
96 end
97
98 function has_ipv6(self)
99 return nfs.access("/proc/net/ipv6_route")
100 end
101
102 function add_network(self, n, options)
103 if n and #n > 0 and n:match("^[a-zA-Z0-9_]+$") and not self:get_network(n) then
104 if ub.uci:section("network", "interface", n, options) then
105 return network(n)
106 end
107 end
108 end
109
110 function get_network(self, n)
111 if n and ub.uci:get("network", n) == "interface" then
112 return network(n)
113 end
114 end
115
116 function get_networks(self)
117 local nets = { }
118 ub.uci:foreach("network", "interface",
119 function(s)
120 nets[#nets+1] = network(s['.name'])
121 end)
122 return nets
123 end
124
125 function del_network(self, n)
126 local r = ub.uci:delete("network", n)
127 if r then
128 ub.uci:foreach("network", "alias",
129 function(s)
130 if s.interface == n then
131 ub.uci:delete("network", s['.name'])
132 end
133 end)
134 ub.uci:foreach("network", "route",
135 function(s)
136 if s.interface == n then
137 ub.uci:delete("network", s['.name'])
138 end
139 end)
140 ub.uci:foreach("network", "route6",
141 function(s)
142 if s.interface == n then
143 ub.uci:delete("network", s['.name'])
144 end
145 end)
146 end
147 return r
148 end
149
150 function rename_network(self, old, new)
151 local r
152 if new and #new > 0 and new:match("^[a-zA-Z0-9_]+$") and not self:get_network(new) then
153 r = ub.uci:section("network", "interface", new,
154 ub.uci:get_all("network", old))
155
156 if r then
157 ub.uci:foreach("network", "alias",
158 function(s)
159 if s.interface == old then
160 ub.uci:set("network", s['.name'], "interface", new)
161 end
162 end)
163 ub.uci:foreach("network", "route",
164 function(s)
165 if s.interface == old then
166 ub.uci:set("network", s['.name'], "interface", new)
167 end
168 end)
169 ub.uci:foreach("network", "route6",
170 function(s)
171 if s.interface == old then
172 ub.uci:set("network", s['.name'], "interface", new)
173 end
174 end)
175 end
176 end
177 return r or false
178 end
179
180 function get_interface(self, i)
181 return ifs[i] and interface(i)
182 end
183
184 function get_interfaces(self)
185 local ifaces = { }
186 local iface
187 for iface, _ in pairs(ifs) do
188 ifaces[#ifaces+1] = interface(iface)
189 end
190 return ifaces
191 end
192
193 function ignore_interface(self, x)
194 return (x:match("^wmaster%d") or x:match("^wifi%d")
195 or x:match("^hwsim%d") or x:match("^imq%d") or x == "lo")
196 end
197
198
199 network = ub:section("interface")
200 network:property("device")
201 network:property("ifname")
202 network:property("proto")
203 network:property("type")
204
205 function network.name(self)
206 return self.sid
207 end
208
209 function network.is_bridge(self)
210 return (self:type() == "bridge")
211 end
212
213 function network.add_interface(self, ifname)
214 if type(ifname) ~= "string" then
215 ifname = ifname:name()
216 end
217 if ifs[ifname] then
218 self:ifname(ub:list((self:ifname() or ''), ifname))
219 end
220 end
221
222 function network.del_interface(self, ifname)
223 if type(ifname) ~= "string" then
224 ifname = ifname:name()
225 end
226 self:ifname(ub:list((self:ifname() or ''), nil, ifname))
227 end
228
229 function network.get_interfaces(self)
230 local ifaces = { }
231 local iface
232 for _, iface in ub:list(
233 (self:ifname() or '') .. ' ' .. (self:device() or '')
234 ) do
235 iface = iface:match("[^:]+")
236 if ifs[iface] then
237 ifaces[#ifaces+1] = interface(iface)
238 end
239 end
240 return ifaces
241 end
242
243 function network.contains_interface(self, iface)
244 local i
245 local ifaces = ub:list(
246 (self:ifname() or '') .. ' ' .. (self:device() or '')
247 )
248
249 if type(iface) ~= "string" then
250 iface = iface:name()
251 end
252
253 for _, i in ipairs(ifaces) do
254 if i == iface then
255 return true
256 end
257 end
258
259 return false
260 end
261
262
263 interface = utl.class()
264 function interface.__init__(self, ifname)
265 if ifs[ifname] then
266 self.ifname = ifname
267 self.dev = ifs[ifname]
268 self.br = brs[ifname]
269 end
270 end
271
272 function interface.name(self)
273 return self.ifname
274 end
275
276 function interface.mac(self)
277 return self.dev.macaddr or "00:00:00:00:00:00"
278 end
279
280 function interface.ipaddrs(self)
281 return self.dev.ipaddrs or { }
282 end
283
284 function interface.ip6addrs(self)
285 return self.dev.ip6addrs or { }
286 end
287
288 function interface.type(self)
289 if iwi.type(self.ifname) and iwi.type(self.ifname) ~= "dummy" then
290 return "wifi"
291 elseif brs[self.ifname] then
292 return "bridge"
293 elseif self.ifname:match("%.") then
294 return "switch"
295 else
296 return "ethernet"
297 end
298 end
299
300 function interface.get_type_i18n(self)
301 local x = self:type()
302 if x == "wifi" then
303 return i18n.translate("a_s_if_wifidev", "Wireless Adapter")
304 elseif x == "bridge" then
305 return i18n.translate("a_s_if_bridge", "Bridge")
306 elseif x == "switch" then
307 return i18n.translate("a_s_if_ethswitch", "Ethernet Switch")
308 else
309 return i18n.translate("a_s_if_ethdev", "Ethernet Adapter")
310 end
311 end
312
313 function interface.ports(self)
314 if self.br then
315 local iface
316 local ifaces = { }
317 for _, iface in ipairs(self.br.ifnames) do
318 ifaces[#ifaces+1] = interface(iface.name)
319 end
320 return ifaces
321 end
322 end
323
324 function interface.bridge_id(self)
325 if self.br then
326 return self.br.id
327 else
328 return nil
329 end
330 end
331
332 function interface.bridge_stp(self)
333 if self.br then
334 return self.br.stp
335 else
336 return false
337 end
338 end
339
340 function interface.is_up(self)
341 return self.dev.flags and self.dev.flags.up
342 end
343
344 function interface.is_bridge(self)
345 return (self:type() == "bridge")
346 end
347
348 function interface.is_bridgeport(self)
349 return self.dev and self.dev.bridge and true or false
350 end
351
352 function interface.tx_bytes(self)
353 return self.dev and self.dev.stats
354 and self.dev.stats.tx_bytes or 0
355 end
356
357 function interface.rx_bytes(self)
358 return self.dev and self.dev.stats
359 and self.dev.stats.rx_bytes or 0
360 end
361
362 function interface.tx_packets(self)
363 return self.dev and self.dev.stats
364 and self.dev.stats.tx_packets or 0
365 end
366
367 function interface.rx_packets(self)
368 return self.dev and self.dev.stats
369 and self.dev.stats.rx_packets or 0
370 end
371
372 function interface.get_network(self)
373 if not self.network then
374 local net
375 for _, net in ipairs(_M:get_networks()) do
376 if net:contains_interface(self.ifname) then
377 self.network = net
378 return net
379 end
380 end
381 else
382 return self.network
383 end
384 end
385