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)
224 for j, _ in pairs(ifs) do
225 if ifs[j].sid == i then
232 function get_interfaces(self)
235 for iface, _ in pairs(ifs) do
236 ifaces[#ifaces+1] = interface(iface)
241 function ignore_interface(self, x)
242 if foreach_handler(function(h) return h:ignore_interface(x) end) then
245 return (x:match("^wmaster%d") or x:match("^wifi%d")
246 or x:match("^hwsim%d") or x:match("^imq%d") or x == "lo")
251 network = ub:section("interface")
252 network:property("device")
253 network:property("ifname")
254 network:property("proto")
255 network:property("type")
257 function network.name(self)
261 function network.is_bridge(self)
262 return (self:type() == "bridge")
265 function network.add_interface(self, ifname)
268 if type(ifname) ~= "string" then
269 ifaces = { ifname:name() }
271 ifaces = ub:list(ifname)
274 for _, iface in ipairs(ifaces) do
276 -- make sure the interface is removed from all networks
277 local i = interface(iface)
278 local n = i:get_network()
279 if n then n:del_interface(iface) end
281 if ifs[iface].handler then
282 ifs[iface].handler:add_interface(self, iface, ifs[iface])
284 self:ifname(ub:list((self:ifname() or ''), iface))
290 function network.del_interface(self, ifname)
291 if type(ifname) ~= "string" then
292 ifname = ifname:name()
295 if ifs[ifname] and ifs[ifname].handler then
296 ifs[ifname].handler:del_interface(self, ifname, ifs[ifname])
298 self:ifname(ub:list((self:ifname() or ''), nil, ifname))
302 function network.get_interfaces(self)
305 for _, iface in ipairs(ub:list(self:ifname())) do
306 iface = iface:match("[^:]+")
308 ifaces[#ifaces+1] = interface(iface)
311 for iface, _ in pairs(ifs) do
312 if ifs[iface].network == self:name() then
313 ifaces[#ifaces+1] = interface(iface)
319 function network.contains_interface(self, iface)
321 local ifaces = ub:list(self:ifname())
323 if type(iface) ~= "string" then
327 for _, i in ipairs(ifaces) do
333 for i, _ in pairs(ifs) do
334 if ifs[i].dev and ifs[i].dev.network == self:name() then
343 interface = utl.class()
344 function interface.__init__(self, ifname)
347 self.dev = ifs[ifname]
348 self.br = brs[ifname]
352 function interface.name(self)
356 function interface.mac(self)
357 return self.dev.macaddr or "00:00:00:00:00:00"
360 function interface.ipaddrs(self)
361 return self.dev.ipaddrs or { }
364 function interface.ip6addrs(self)
365 return self.dev.ip6addrs or { }
368 function interface.type(self)
369 if self.dev and self.dev.type then
371 elseif brs[self.ifname] then
373 elseif sws[self.ifname] or self.ifname:match("%.") then
380 function interface.shortname(self)
381 if self.dev and self.dev.handler then
382 return self.dev.handler:shortname(self)
388 function interface.get_i18n(self)
389 if self.dev and self.dev.handler then
390 return self.dev.handler:get_i18n(self)
392 return "%s: %q" %{ self:get_type_i18n(), self:name() }
396 function interface.get_type_i18n(self)
397 local x = self:type()
399 return i18n.translate("Wireless Adapter")
400 elseif x == "bridge" then
401 return i18n.translate("Bridge")
402 elseif x == "switch" then
403 return i18n.translate("Ethernet Switch")
405 return i18n.translate("Ethernet Adapter")
409 function interface.ports(self)
413 for _, iface in ipairs(self.br.ifnames) do
414 ifaces[#ifaces+1] = interface(iface.name)
420 function interface.bridge_id(self)
428 function interface.bridge_stp(self)
436 function interface.is_up(self)
437 return self.dev.flags and self.dev.flags.up
440 function interface.is_bridge(self)
441 return (self:type() == "bridge")
444 function interface.is_bridgeport(self)
445 return self.dev and self.dev.bridge and true or false
448 function interface.tx_bytes(self)
449 return self.dev and self.dev.stats
450 and self.dev.stats.tx_bytes or 0
453 function interface.rx_bytes(self)
454 return self.dev and self.dev.stats
455 and self.dev.stats.rx_bytes or 0
458 function interface.tx_packets(self)
459 return self.dev and self.dev.stats
460 and self.dev.stats.tx_packets or 0
463 function interface.rx_packets(self)
464 return self.dev and self.dev.stats
465 and self.dev.stats.rx_packets or 0
468 function interface.get_network(self)
469 if self.dev and self.dev.network then
470 self.network = _M:get_network(self.dev.network)
473 if not self.network then
475 for _, net in ipairs(_M:get_networks()) do
476 if net:contains_interface(self.ifname) then