4e669f307f2b80b2369dd238aba850b802aed62b
[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 = type, pairs, ipairs, table
21
22 local lmo = require "lmo"
23 local nxo = require "nixio"
24 local iwi = require "iwinfo"
25 local ipc = require "luci.ip"
26 local utl = require "luci.util"
27 local uct = require "luci.model.uci.bind"
28
29 module "luci.model.network"
30
31
32 local ub = uct.bind("network")
33 local ifs, brs
34
35 function init(cursor)
36         if cursor then
37                 cursor:unload("network")
38                 cursor:load("network")
39                 ub:init(cursor)
40
41                 ifs = { }
42                 brs = { }
43
44                 -- read interface information
45                 local n, i
46                 for n, i in ipairs(nxo.getifaddrs()) do
47                         local name = i.name:match("[^:]+")
48
49                         if not _M:ignore_interface(name) then
50                                 ifs[name] = ifs[name] or {
51                                         idx      = i.ifindex or n,
52                                         name     = name,
53                                         rawname  = i.name,
54                                         flags    = { },
55                                         ipaddrs  = { },
56                                         ip6addrs = { }
57                                 }
58
59                                 if i.family == "packet" then
60                                         ifs[name].flags   = i.flags
61                                         ifs[name].stats   = i.data
62                                         ifs[name].macaddr = i.addr
63                                 elseif i.family == "inet" then
64                                         ifs[name].ipaddrs[#ifs[name].ipaddrs+1] = ipc.IPv4(i.addr, i.netmask)
65                                 elseif i.family == "inet6" then
66                                         ifs[name].ip6addrs[#ifs[name].ip6addrs+1] = ipc.IPv6(i.addr, i.netmask)
67                                 end
68                         end
69                 end             
70
71                 -- read bridge informaton
72                 local b, l
73                 for l in utl.execi("brctl show") do
74                         if not l:match("STP") then
75                                 local r = utl.split(l, "%s+", nil, true)
76                                 if #r == 4 then
77                                         b = {
78                                                 name    = r[1],
79                                                 id      = r[2],
80                                                 stp     = r[3] == "yes",
81                                                 ifnames = { ifs[r[4]] }
82                                         }
83                                         if b.ifnames[1] then
84                                                 b.ifnames[1].bridge = b
85                                         end
86                                         brs[r[1]] = b
87                                 elseif b then
88                                         b.ifnames[#b.ifnames+1] = ifs[r[2]]
89                                         b.ifnames[#b.ifnames].bridge = b
90                                 end
91                         end
92                 end
93         end
94 end
95
96 function add_network(self, n, options)
97         if n and #n > 0 and n:match("^[a-zA-Z0-9_]+$") and not self:get_network(n) then
98                 if ub.uci:section("network", "interface", n, options) then
99                         return network(n)
100                 end
101         end
102 end
103
104 function get_network(self, n)
105         if n and ub.uci:get("network", n) == "interface" then
106                 return network(n)
107         end
108 end
109
110 function get_networks(self)
111         local nets = { }
112         ub.uci:foreach("network", "interface",
113                 function(s)
114                         nets[#nets+1] = network(s['.name'])
115                 end)
116         return nets
117 end
118
119 function del_network(self, n)
120         local r = ub.uci:delete("network", n)
121         if r then
122                 ub.uci:foreach("network", "alias",
123                         function(s)
124                                 if s.interface == n then
125                                         ub.uci:delete("network", s['.name'])
126                                 end
127                         end)
128                 ub.uci:foreach("network", "route",
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", "route6",
135                         function(s)
136                                 if s.interface == n then
137                                         ub.uci:delete("network", s['.name'])
138                                 end
139                         end)
140         end
141         return r
142 end
143
144 function rename_network(self, old, new)
145         local r
146         if new and #new > 0 and new:match("^[a-zA-Z0-9_]+$") and not self:get_network(new) then
147                 r = ub.uci:section("network", "interface", new,
148                         ub.uci:get_all("network", old))
149
150                 if r then
151                         ub.uci:foreach("network", "alias",
152                                 function(s)
153                                         if s.interface == old then
154                                                 ub.uci:set("network", s['.name'], "interface", new)
155                                         end
156                                 end)
157                         ub.uci:foreach("network", "route",
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", "route6",
164                                 function(s)
165                                         if s.interface == old then
166                                                 ub.uci:set("network", s['.name'], "interface", new)
167                                         end
168                                 end)
169                 end
170         end
171         return r or false
172 end
173
174 function get_interface(self, i)
175         return ifs[i] and interface(i)
176 end
177
178 function get_interfaces(self)
179         local ifaces = { }
180         local iface
181         for iface, _ in pairs(ifs) do
182                 ifaces[#ifaces+1] = interface(iface)
183         end
184         return ifaces
185 end
186
187 function ignore_interface(self, x)
188         return (x:match("^wmaster%d") or x:match("^wifi%d")
189                 or x:match("^hwsim%d") or x:match("^imq%d") or x == "lo")
190 end
191
192
193 network = ub:section("interface")
194 network:property("device")
195 network:property("ifname")
196 network:property("proto")
197 network:property("type")
198
199 function network.name(self)
200         return self.sid
201 end
202
203 function network.is_bridge(self)
204         return (self:type() == "bridge")
205 end
206
207 function network.add_interface(self, ifname)
208         if type(ifname) ~= "string" then
209                 ifname = ifname:ifname()
210         end
211         if ifs[ifname] then
212                 self:ifname(ub:list((self:ifname() or ''), ifname))
213         end
214 end
215
216 function network.del_interface(self, ifname)
217         if type(ifname) ~= "string" then
218                 ifname = ifname:ifname()
219         end
220         self:ifname(ub:list((self:ifname() or ''), nil, ifname))
221 end
222
223 function network.get_interfaces(self)
224         local ifaces = { }
225         local iface
226         for _, iface in ub:list(
227                 (self:ifname() or '') .. ' ' .. (self:device() or '')
228         ) do
229                 iface = iface:match("[^:]+")
230                 if ifs[iface] then
231                         ifaces[#ifaces+1] = interface(iface)
232                 end
233         end
234         return ifaces
235 end
236
237 function contains_interface(self, iface)
238         local i
239         local ifaces = ub:list(
240                 (self:ifname() or '') .. ' ' .. (self:device() or '')
241         )
242
243         if type(iface) ~= "string" then
244                 iface = iface:ifname()
245         end
246
247         for _, i in ipairs(ifaces) do
248                 if i == iface then
249                         return true
250                 end
251         end
252
253         return false
254 end
255
256
257 interface = utl.class()
258 function interface.__init__(self, ifname)
259         if ifs[ifname] then
260                 self.ifname = ifname
261                 self.dev    = ifs[ifname]
262                 self.br     = brs[ifname]
263         end
264 end
265
266 function interface.name(self)
267         return self.ifname
268 end
269
270 function interface.type(self)
271         if iwi.type(self.ifname) and iwi.type(self.ifname) ~= "dummy" then
272                 return "wifi"
273         elseif brs[self.ifname] then
274                 return "bridge"
275         elseif self.ifname:match("%.") then
276                 return "switch"
277         else
278                 return "ethernet"
279         end
280 end
281
282 function interface.ports(self)
283         if self.br then
284                 local iface
285                 local ifaces = { }
286                 for _, iface in ipairs(self.br.ifnames) do
287                         ifaces[#ifaces+1] = interface(iface)
288                 end
289                 return ifaces
290         end
291 end
292
293 function interface.is_up(self)
294         return self.dev.flags and self.dev.flags.up
295 end
296
297 function interface.is_bridge(self)
298         return (self:type() == "bridge")
299 end
300
301 function interface.get_network(self)
302         local net
303         for _, net in ipairs(_M:get_networks()) do
304                 if net:contains_interface(self.ifname) then
305                         return net
306                 end
307         end
308 end
309