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