root/luci/trunk/libs/core/luasrc/model/network.lua @ 5405

Revision 5405, 9.9 KB (checked in by jow, 4 years ago)

libs/core: implement special treatment of wireless in network model

  • Property svn:keywords set to Id
Line 
1--[[
2LuCI - Network model
3
4Copyright 2009 Jo-Philipp Wich <xm@subsignal.org>
5
6Licensed under the Apache License, Version 2.0 (the "License");
7you may not use this file except in compliance with the License.
8You may obtain a copy of the License at
9
10    http://www.apache.org/licenses/LICENSE-2.0
11
12Unless required by applicable law or agreed to in writing, software
13distributed under the License is distributed on an "AS IS" BASIS,
14WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15See the License for the specific language governing permissions and
16limitations under the License.
17
18]]--
19
20local type, pairs, ipairs, loadfile, table, i18n
21    = type, pairs, ipairs, loadfile, table, luci.i18n
22
23local lmo = require "lmo"
24local nxo = require "nixio"
25local nfs = require "nixio.fs"
26local iwi = require "iwinfo"
27local ipc = require "luci.ip"
28local utl = require "luci.util"
29local uct = require "luci.model.uci.bind"
30
31module "luci.model.network"
32
33-- load extensions
34local ext
35local handler = { }
36
37for ext in nfs.glob(utl.libpath() .. "/model/network/*.lua") do
38    if nfs.access(ext) then
39        local m = loadfile(ext)
40        if m then
41            handler[#handler+1] = m()
42        end
43    end
44end
45
46function foreach_handler(code, ...)
47    local h
48    for _, h in ipairs(handler) do
49        if code(h, ...) then
50            return true
51        end
52    end
53    return false
54end
55
56local ub = uct.bind("network")
57local ifs, brs, sws
58
59function init(cursor)
60    if cursor then
61        cursor:unload("network")
62        cursor:load("network")
63        ub:init(cursor)
64
65        ifs = { }
66        brs = { }
67        sws = { }
68
69        -- init handler
70        foreach_handler(function(h)
71            h:init(cursor)
72            h:find_interfaces(ifs, brs)
73        end)
74
75        -- read interface information
76        local n, i
77        for n, i in ipairs(nxo.getifaddrs()) do
78            local name = i.name:match("[^:]+")
79            local prnt = name:match("^([^%.]+)%.")
80
81            if not _M:ignore_interface(name) then
82                ifs[name] = ifs[name] or {
83                    idx      = i.ifindex or n,
84                    name     = name,
85                    rawname  = i.name,
86                    flags    = { },
87                    ipaddrs  = { },
88                    ip6addrs = { }
89                }
90
91                if prnt then
92                    sws[name] = true
93                    sws[prnt] = true
94                end
95
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)
104                end
105            end
106        end
107
108        -- read bridge informaton
109        local b, l
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)
113                if #r == 4 then
114                    b = {
115                        name    = r[1],
116                        id      = r[2],
117                        stp     = r[3] == "yes",
118                        ifnames = { ifs[r[4]] }
119                    }
120                    if b.ifnames[1] then
121                        b.ifnames[1].bridge = b
122                    end
123                    brs[r[1]] = b
124                elseif b then
125                    b.ifnames[#b.ifnames+1] = ifs[r[2]]
126                    b.ifnames[#b.ifnames].bridge = b
127                end
128            end
129        end
130    end
131end
132
133function has_ipv6(self)
134    return nfs.access("/proc/net/ipv6_route")
135end
136
137function 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
140            return network(n)
141        end
142    end
143end
144
145function get_network(self, n)
146    if n and ub.uci:get("network", n) == "interface" then
147        return network(n)
148    end
149end
150
151function get_networks(self)
152    local nets = { }
153    ub.uci:foreach("network", "interface",
154        function(s)
155            nets[#nets+1] = network(s['.name'])
156        end)
157    return nets
158end
159
160function del_network(self, n)
161    local r = ub.uci:delete("network", n)
162    if r then
163        ub.uci:foreach("network", "alias",
164            function(s)
165                if s.interface == n then
166                    ub.uci:delete("network", s['.name'])
167                end
168            end)
169        ub.uci:foreach("network", "route",
170            function(s)
171                if s.interface == n then
172                    ub.uci:delete("network", s['.name'])
173                end
174            end)
175        ub.uci:foreach("network", "route6",
176            function(s)
177                if s.interface == n then
178                    ub.uci:delete("network", s['.name'])
179                end
180            end)
181
182        foreach_handler(function(h) h:del_network(n) end)
183    end
184    return r
185end
186
187function rename_network(self, old, new)
188    local r
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))
192
193        if r then
194            ub.uci:foreach("network", "alias",
195                function(s)
196                    if s.interface == old then
197                        ub.uci:set("network", s['.name'], "interface", new)
198                    end
199                end)
200            ub.uci:foreach("network", "route",
201                function(s)
202                    if s.interface == old then
203                        ub.uci:set("network", s['.name'], "interface", new)
204                    end
205                end)
206            ub.uci:foreach("network", "route6",
207                function(s)
208                    if s.interface == old then
209                        ub.uci:set("network", s['.name'], "interface", new)
210                    end
211                end)
212
213            foreach_handler(function(h) h:rename_network(old, new) end)
214        end
215    end
216    return r or false
217end
218
219function get_interface(self, i)
220    return ifs[i] and interface(i)
221end
222
223function get_interfaces(self)
224    local ifaces = { }
225    local iface
226    for iface, _ in pairs(ifs) do
227        ifaces[#ifaces+1] = interface(iface)
228    end
229    return ifaces
230end
231
232function ignore_interface(self, x)
233    if foreach_handler(function(h) return h:ignore_interface(x) end) then
234        return true
235    else
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")
238    end
239end
240
241
242network = ub:section("interface")
243network:property("device")
244network:property("ifname")
245network:property("proto")
246network:property("type")
247
248function network.name(self)
249    return self.sid
250end
251
252function network.is_bridge(self)
253    return (self:type() == "bridge")
254end
255
256function network.add_interface(self, ifname)
257    local ifaces, iface
258
259    if type(ifname) ~= "string" then
260        ifaces = { ifname:name() }
261    else
262        ifaces = ub:list(ifname)
263    end
264
265    for _, iface in ipairs(ifaces) do
266        if ifs[iface] then
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
271
272            if ifs[iface].handler then
273                ifs[iface].handler:add_interface(self, iface, ifs[iface])
274            else
275                self:ifname(ub:list((self:ifname() or ''), iface))
276            end
277        end
278    end
279end
280
281function network.del_interface(self, ifname)
282    if type(ifname) ~= "string" then
283        ifname = ifname:name()
284    end
285
286    if ifs[ifname] and ifs[ifname].handler then
287        ifs[ifname].handler:del_interface(self, ifname, ifs[ifname])
288    else
289        self:ifname(ub:list((self:ifname() or ''), nil, ifname))
290    end
291end
292
293function network.get_interfaces(self)
294    local ifaces = { }
295    local iface
296    for _, iface in ipairs(ub:list(self:ifname())) do
297        iface = iface:match("[^:]+")
298        if ifs[iface] then
299            ifaces[#ifaces+1] = interface(iface)
300        end
301    end
302    for iface, _ in pairs(ifs) do
303        if ifs[iface].network == self:name() then
304            ifaces[#ifaces+1] = interface(iface)
305        end
306    end
307    return ifaces
308end
309
310function network.contains_interface(self, iface)
311    local i
312    local ifaces = ub:list(self:ifname())
313
314    if type(iface) ~= "string" then
315        iface = iface:name()
316    end
317
318    for _, i in ipairs(ifaces) do
319        if i == iface then
320            return true
321        end
322    end
323
324    for i, _ in pairs(ifs) do
325        if ifs[i].dev and ifs[i].dev.network == self:name() then
326            return true
327        end
328    end
329
330    return false
331end
332
333
334interface = utl.class()
335function interface.__init__(self, ifname)
336    if ifs[ifname] then
337        self.ifname = ifname
338        self.dev    = ifs[ifname]
339        self.br     = brs[ifname]
340    end
341end
342
343function interface.name(self)
344    return self.ifname
345end
346
347function interface.mac(self)
348    return self.dev.macaddr or "00:00:00:00:00:00"
349end
350
351function interface.ipaddrs(self)
352    return self.dev.ipaddrs or { }
353end
354
355function interface.ip6addrs(self)
356    return self.dev.ip6addrs or { }
357end
358
359function interface.type(self)
360    if self.dev and self.dev.type then
361        return self.dev.type
362    elseif brs[self.ifname] then
363        return "bridge"
364    elseif sws[self.ifname] or self.ifname:match("%.") then
365        return "switch"
366    else
367        return "ethernet"
368    end
369end
370
371function interface.shortname(self)
372    if self.dev and self.dev.handler then
373        return self.dev.handler:shortname(self)
374    else
375        return self.ifname
376    end
377end
378
379function interface.get_i18n(self)
380    if self.dev and self.dev.handler then
381        return self.dev.handler:get_i18n(self)
382    else
383        return "%s: %q" %{ self:get_type_i18n(), self:name() }
384    end
385end
386
387function interface.get_type_i18n(self)
388    local x = self:type()
389    if x == "wifi" then
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")
395    else
396        return i18n.translate("a_s_if_ethdev", "Ethernet Adapter")
397    end
398end
399
400function interface.ports(self)
401    if self.br then
402        local iface
403        local ifaces = { }
404        for _, iface in ipairs(self.br.ifnames) do
405            ifaces[#ifaces+1] = interface(iface.name)
406        end
407        return ifaces
408    end
409end
410
411function interface.bridge_id(self)
412    if self.br then
413        return self.br.id
414    else
415        return nil
416    end
417end
418
419function interface.bridge_stp(self)
420    if self.br then
421        return self.br.stp
422    else
423        return false
424    end
425end
426
427function interface.is_up(self)
428    return self.dev.flags and self.dev.flags.up
429end
430
431function interface.is_bridge(self)
432    return (self:type() == "bridge")
433end
434
435function interface.is_bridgeport(self)
436    return self.dev and self.dev.bridge and true or false
437end
438
439function interface.tx_bytes(self)
440    return self.dev and self.dev.stats
441        and self.dev.stats.tx_bytes or 0
442end
443
444function interface.rx_bytes(self)
445    return self.dev and self.dev.stats
446        and self.dev.stats.rx_bytes or 0
447end
448
449function interface.tx_packets(self)
450    return self.dev and self.dev.stats
451        and self.dev.stats.tx_packets or 0
452end
453
454function interface.rx_packets(self)
455    return self.dev and self.dev.stats
456        and self.dev.stats.rx_packets or 0
457end
458
459function interface.get_network(self)
460    if self.dev and self.dev.network then
461        self.network = _M:get_network(self.dev.network)
462    end
463
464    if not self.network then
465        local net
466        for _, net in ipairs(_M:get_networks()) do
467            if net:contains_interface(self.ifname) then
468                self.network = net
469                return net
470            end
471        end
472    else
473        return self.network
474    end
475end
476
Note: See TracBrowser for help on using the browser.