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