diff options
-rw-r--r-- | libs/core/luasrc/model/network.lua | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/libs/core/luasrc/model/network.lua b/libs/core/luasrc/model/network.lua new file mode 100644 index 000000000..4e669f307 --- /dev/null +++ b/libs/core/luasrc/model/network.lua @@ -0,0 +1,309 @@ +--[[ +LuCI - Network model + +Copyright 2009 Jo-Philipp Wich <xm@subsignal.org> + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +]]-- + +local type, pairs, ipairs, table = type, pairs, ipairs, table + +local lmo = require "lmo" +local nxo = require "nixio" +local iwi = require "iwinfo" +local ipc = require "luci.ip" +local utl = require "luci.util" +local uct = require "luci.model.uci.bind" + +module "luci.model.network" + + +local ub = uct.bind("network") +local ifs, brs + +function init(cursor) + if cursor then + cursor:unload("network") + cursor:load("network") + ub:init(cursor) + + ifs = { } + brs = { } + + -- read interface information + local n, i + for n, i in ipairs(nxo.getifaddrs()) do + local name = i.name:match("[^:]+") + + if not _M:ignore_interface(name) then + ifs[name] = ifs[name] or { + idx = i.ifindex or n, + name = name, + rawname = i.name, + flags = { }, + ipaddrs = { }, + ip6addrs = { } + } + + if i.family == "packet" then + ifs[name].flags = i.flags + ifs[name].stats = i.data + ifs[name].macaddr = i.addr + elseif i.family == "inet" then + ifs[name].ipaddrs[#ifs[name].ipaddrs+1] = ipc.IPv4(i.addr, i.netmask) + elseif i.family == "inet6" then + ifs[name].ip6addrs[#ifs[name].ip6addrs+1] = ipc.IPv6(i.addr, i.netmask) + end + end + end + + -- read bridge informaton + local b, l + for l in utl.execi("brctl show") do + if not l:match("STP") then + local r = utl.split(l, "%s+", nil, true) + if #r == 4 then + b = { + name = r[1], + id = r[2], + stp = r[3] == "yes", + ifnames = { ifs[r[4]] } + } + if b.ifnames[1] then + b.ifnames[1].bridge = b + end + brs[r[1]] = b + elseif b then + b.ifnames[#b.ifnames+1] = ifs[r[2]] + b.ifnames[#b.ifnames].bridge = b + end + end + end + end +end + +function add_network(self, n, options) + if n and #n > 0 and n:match("^[a-zA-Z0-9_]+$") and not self:get_network(n) then + if ub.uci:section("network", "interface", n, options) then + return network(n) + end + end +end + +function get_network(self, n) + if n and ub.uci:get("network", n) == "interface" then + return network(n) + end +end + +function get_networks(self) + local nets = { } + ub.uci:foreach("network", "interface", + function(s) + nets[#nets+1] = network(s['.name']) + end) + return nets +end + +function del_network(self, n) + local r = ub.uci:delete("network", n) + if r then + ub.uci:foreach("network", "alias", + function(s) + if s.interface == n then + ub.uci:delete("network", s['.name']) + end + end) + ub.uci:foreach("network", "route", + function(s) + if s.interface == n then + ub.uci:delete("network", s['.name']) + end + end) + ub.uci:foreach("network", "route6", + function(s) + if s.interface == n then + ub.uci:delete("network", s['.name']) + end + end) + end + return r +end + +function rename_network(self, old, new) + local r + if new and #new > 0 and new:match("^[a-zA-Z0-9_]+$") and not self:get_network(new) then + r = ub.uci:section("network", "interface", new, + ub.uci:get_all("network", old)) + + if r then + ub.uci:foreach("network", "alias", + function(s) + if s.interface == old then + ub.uci:set("network", s['.name'], "interface", new) + end + end) + ub.uci:foreach("network", "route", + function(s) + if s.interface == old then + ub.uci:set("network", s['.name'], "interface", new) + end + end) + ub.uci:foreach("network", "route6", + function(s) + if s.interface == old then + ub.uci:set("network", s['.name'], "interface", new) + end + end) + end + end + return r or false +end + +function get_interface(self, i) + return ifs[i] and interface(i) +end + +function get_interfaces(self) + local ifaces = { } + local iface + for iface, _ in pairs(ifs) do + ifaces[#ifaces+1] = interface(iface) + end + return ifaces +end + +function ignore_interface(self, x) + return (x:match("^wmaster%d") or x:match("^wifi%d") + or x:match("^hwsim%d") or x:match("^imq%d") or x == "lo") +end + + +network = ub:section("interface") +network:property("device") +network:property("ifname") +network:property("proto") +network:property("type") + +function network.name(self) + return self.sid +end + +function network.is_bridge(self) + return (self:type() == "bridge") +end + +function network.add_interface(self, ifname) + if type(ifname) ~= "string" then + ifname = ifname:ifname() + end + if ifs[ifname] then + self:ifname(ub:list((self:ifname() or ''), ifname)) + end +end + +function network.del_interface(self, ifname) + if type(ifname) ~= "string" then + ifname = ifname:ifname() + end + self:ifname(ub:list((self:ifname() or ''), nil, ifname)) +end + +function network.get_interfaces(self) + local ifaces = { } + local iface + for _, iface in ub:list( + (self:ifname() or '') .. ' ' .. (self:device() or '') + ) do + iface = iface:match("[^:]+") + if ifs[iface] then + ifaces[#ifaces+1] = interface(iface) + end + end + return ifaces +end + +function contains_interface(self, iface) + local i + local ifaces = ub:list( + (self:ifname() or '') .. ' ' .. (self:device() or '') + ) + + if type(iface) ~= "string" then + iface = iface:ifname() + end + + for _, i in ipairs(ifaces) do + if i == iface then + return true + end + end + + return false +end + + +interface = utl.class() +function interface.__init__(self, ifname) + if ifs[ifname] then + self.ifname = ifname + self.dev = ifs[ifname] + self.br = brs[ifname] + end +end + +function interface.name(self) + return self.ifname +end + +function interface.type(self) + if iwi.type(self.ifname) and iwi.type(self.ifname) ~= "dummy" then + return "wifi" + elseif brs[self.ifname] then + return "bridge" + elseif self.ifname:match("%.") then + return "switch" + else + return "ethernet" + end +end + +function interface.ports(self) + if self.br then + local iface + local ifaces = { } + for _, iface in ipairs(self.br.ifnames) do + ifaces[#ifaces+1] = interface(iface) + end + return ifaces + end +end + +function interface.is_up(self) + return self.dev.flags and self.dev.flags.up +end + +function interface.is_bridge(self) + return (self:type() == "bridge") +end + +function interface.get_network(self) + local net + for _, net in ipairs(_M:get_networks()) do + if net:contains_interface(self.ifname) then + return net + end + end +end + |