4 Copyright 2009 Jo-Philipp Wich <xm@subsignal.org>
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
10 http://www.apache.org/licenses/LICENSE-2.0
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.
20 local type, pairs, ipairs, loadfile, table, i18n
21 = type, pairs, ipairs, loadfile, table, luci.i18n
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"
31 module "luci.model.network"
37 for ext in nfs.glob(utl.libpath() .. "/model/network/*.lua") do
38 if nfs.access(ext) then
39 local m = loadfile(ext)
41 handler[#handler+1] = m()
46 function foreach_handler(code, ...)
48 for _, h in ipairs(handler) do
56 local ub = uct.bind("network")
61 cursor:unload("network")
62 cursor:load("network")
70 foreach_handler(function(h)
72 h:find_interfaces(ifs, brs)
75 -- read interface information
77 for n, i in ipairs(nxo.getifaddrs()) do
78 local name = i.name:match("[^:]+")
79 local prnt = name:match("^([^%.]+)%.")
81 if not _M:ignore_interface(name) then
82 ifs[name] = ifs[name] or {
96 if i.family == "packet" then
97 ifs[name].flags = i.flags
98 ifs[name].stats = i.data
99 ifs[name].macaddr = i.addr
100 elseif i.family == "inet" then
101 ifs[name].ipaddrs[#ifs[name].ipaddrs+1] = ipc.IPv4(i.addr, i.netmask)
102 elseif i.family == "inet6" then
103 ifs[name].ip6addrs[#ifs[name].ip6addrs+1] = ipc.IPv6(i.addr, i.netmask)
108 -- read bridge informaton
110 for l in utl.execi("brctl show") do
111 if not l:match("STP") then
112 local r = utl.split(l, "%s+", nil, true)
118 ifnames = { ifs[r[4]] }
121 b.ifnames[1].bridge = b
125 b.ifnames[#b.ifnames+1] = ifs[r[2]]
126 b.ifnames[#b.ifnames].bridge = b
133 function has_ipv6(self)
134 return nfs.access("/proc/net/ipv6_route")
137 function add_network(self, n, options)
138 if n and #n > 0 and n:match("^[a-zA-Z0-9_]+$") and not self:get_network(n) then
139 if ub.uci:section("network", "interface", n, options) then
145 function get_network(self, n)
146 if n and ub.uci:get("network", n) == "interface" then
151 function get_networks(self)
153 ub.uci:foreach("network", "interface",
155 nets[#nets+1] = network(s['.name'])
160 function del_network(self, n)
161 local r = ub.uci:delete("network", n)
163 ub.uci:foreach("network", "alias",
165 if s.interface == n then
166 ub.uci:delete("network", s['.name'])
169 ub.uci:foreach("network", "route",
171 if s.interface == n then
172 ub.uci:delete("network", s['.name'])
175 ub.uci:foreach("network", "route6",
177 if s.interface == n then
178 ub.uci:delete("network", s['.name'])
182 foreach_handler(function(h) h:del_network(n) end)
187 function rename_network(self, old, new)
189 if new and #new > 0 and new:match("^[a-zA-Z0-9_]+$") and not self:get_network(new) then
190 r = ub.uci:section("network", "interface", new,
191 ub.uci:get_all("network", old))
194 ub.uci:foreach("network", "alias",
196 if s.interface == old then
197 ub.uci:set("network", s['.name'], "interface", new)
200 ub.uci:foreach("network", "route",
202 if s.interface == old then
203 ub.uci:set("network", s['.name'], "interface", new)
206 ub.uci:foreach("network", "route6",
208 if s.interface == old then
209 ub.uci:set("network", s['.name'], "interface", new)
213 foreach_handler(function(h) h:rename_network(old, new) end)
219 function get_interface(self, i)
220 return ifs[i] and interface(i)
223 function get_interfaces(self)
226 for iface, _ in pairs(ifs) do
227 ifaces[#ifaces+1] = interface(iface)
232 function ignore_interface(self, x)
233 if foreach_handler(function(h) return h:ignore_interface(x) end) then
236 return (x:match("^wmaster%d") or x:match("^wifi%d")
237 or x:match("^hwsim%d") or x:match("^imq%d") or x == "lo")
242 network = ub:section("interface")
243 network:property("device")
244 network:property("ifname")
245 network:property("proto")
246 network:property("type")
248 function network.name(self)
252 function network.is_bridge(self)
253 return (self:type() == "bridge")
256 function network.add_interface(self, ifname)
259 if type(ifname) ~= "string" then
260 ifaces = { ifname:name() }
262 ifaces = ub:list(ifname)
265 for _, iface in ipairs(ifaces) do
267 -- make sure the interface is removed from all networks
268 local i = interface(iface)
269 local n = i:get_network()
270 if n then n:del_interface(iface) end
272 if ifs[iface].handler then
273 ifs[iface].handler:add_interface(self, iface, ifs[iface])
275 self:ifname(ub:list((self:ifname() or ''), iface))
281 function network.del_interface(self, ifname)
282 if type(ifname) ~= "string" then
283 ifname = ifname:name()
286 if ifs[ifname] and ifs[ifname].handler then
287 ifs[ifname].handler:del_interface(self, ifname, ifs[ifname])
289 self:ifname(ub:list((self:ifname() or ''), nil, ifname))
293 function network.get_interfaces(self)
296 for _, iface in ipairs(ub:list(self:ifname())) do
297 iface = iface:match("[^:]+")
299 ifaces[#ifaces+1] = interface(iface)
302 for iface, _ in pairs(ifs) do
303 if ifs[iface].network == self:name() then
304 ifaces[#ifaces+1] = interface(iface)
310 function network.contains_interface(self, iface)
312 local ifaces = ub:list(self:ifname())
314 if type(iface) ~= "string" then
318 for _, i in ipairs(ifaces) do
324 for i, _ in pairs(ifs) do
325 if ifs[i].dev and ifs[i].dev.network == self:name() then
334 interface = utl.class()
335 function interface.__init__(self, ifname)
338 self.dev = ifs[ifname]
339 self.br = brs[ifname]
343 function interface.name(self)
347 function interface.mac(self)
348 return self.dev.macaddr or "00:00:00:00:00:00"
351 function interface.ipaddrs(self)
352 return self.dev.ipaddrs or { }
355 function interface.ip6addrs(self)
356 return self.dev.ip6addrs or { }
359 function interface.type(self)
360 if self.dev and self.dev.type then
362 elseif brs[self.ifname] then
364 elseif sws[self.ifname] or self.ifname:match("%.") then
371 function interface.shortname(self)
372 if self.dev and self.dev.handler then
373 return self.dev.handler:shortname(self)
379 function interface.get_i18n(self)
380 if self.dev and self.dev.handler then
381 return self.dev.handler:get_i18n(self)
383 return "%s: %q" %{ self:get_type_i18n(), self:name() }
387 function interface.get_type_i18n(self)
388 local x = self:type()
390 return i18n.translate("a_s_if_wifidev", "Wireless Adapter")
391 elseif x == "bridge" then
392 return i18n.translate("a_s_if_bridge", "Bridge")
393 elseif x == "switch" then
394 return i18n.translate("a_s_if_ethswitch", "Ethernet Switch")
396 return i18n.translate("a_s_if_ethdev", "Ethernet Adapter")
400 function interface.ports(self)
404 for _, iface in ipairs(self.br.ifnames) do
405 ifaces[#ifaces+1] = interface(iface.name)
411 function interface.bridge_id(self)
419 function interface.bridge_stp(self)
427 function interface.is_up(self)
428 return self.dev.flags and self.dev.flags.up
431 function interface.is_bridge(self)
432 return (self:type() == "bridge")
435 function interface.is_bridgeport(self)
436 return self.dev and self.dev.bridge and true or false
439 function interface.tx_bytes(self)
440 return self.dev and self.dev.stats
441 and self.dev.stats.tx_bytes or 0
444 function interface.rx_bytes(self)
445 return self.dev and self.dev.stats
446 and self.dev.stats.rx_bytes or 0
449 function interface.tx_packets(self)
450 return self.dev and self.dev.stats
451 and self.dev.stats.tx_packets or 0
454 function interface.rx_packets(self)
455 return self.dev and self.dev.stats
456 and self.dev.stats.rx_packets or 0
459 function interface.get_network(self)
460 if self.dev and self.dev.network then
461 self.network = _M:get_network(self.dev.network)
464 if not self.network then
466 for _, net in ipairs(_M:get_networks()) do
467 if net:contains_interface(self.ifname) then