X-Git-Url: http://git.openwrt.org/?p=project%2Fluci.git;a=blobdiff_plain;f=libs%2Fcore%2Fluasrc%2Fmodel%2Fnetwork.lua;h=cc572298c69b5262f02af232ab45040a528c0627;hp=dd2bdfb90633517a20677dcd4d54f1b10e7d4941;hb=8772db16759352146a069f2bb7394a4a4213ba0f;hpb=2c316a6aabb04d319637128d1c734817e48c8308 diff --git a/libs/core/luasrc/model/network.lua b/libs/core/luasrc/model/network.lua index dd2bdfb906..cc572298c6 100644 --- a/libs/core/luasrc/model/network.lua +++ b/libs/core/luasrc/model/network.lua @@ -17,11 +17,14 @@ limitations under the License. ]]-- -local type, next, pairs, ipairs, loadfile, table, tonumber, math, i18n - = type, next, pairs, ipairs, loadfile, table, tonumber, math, luci.i18n +local type, next, pairs, ipairs, loadfile, table + = type, next, pairs, ipairs, loadfile, table + +local tonumber, tostring, math = tonumber, tostring, math local require = require +local bus = require "ubus" local nxo = require "nixio" local nfs = require "nixio.fs" local ipc = require "luci.ip" @@ -29,12 +32,13 @@ local sys = require "luci.sys" local utl = require "luci.util" local dsp = require "luci.dispatcher" local uci = require "luci.model.uci" +local lng = require "luci.i18n" module "luci.model.network" IFACE_PATTERNS_VIRTUAL = { } -IFACE_PATTERNS_IGNORE = { "^wmaster%d", "^wifi%d", "^hwsim%d", "^imq%d", "^ifb%d", "^mon%.wlan%d", "^sit%d", "^lo$" } +IFACE_PATTERNS_IGNORE = { "^wmaster%d", "^wifi%d", "^hwsim%d", "^imq%d", "^ifb%d", "^mon%.wlan%d", "^sit%d", "^gre%d", "^lo$" } IFACE_PATTERNS_WIRELESS = { "^wlan%d", "^wl%d", "^ath%d", "^%w+%.network%d" } @@ -43,6 +47,7 @@ protocol = utl.class() local _protocols = { } local _interfaces, _bridge, _switch, _tunnel +local _ubus, _ubusnetcache, _ubusdevcache local _uci_real, _uci_state function _filter(c, s, o, r) @@ -196,6 +201,10 @@ function init(cursor) _switch = { } _tunnel = { } + _ubus = bus.connect() + _ubusnetcache = { } + _ubusdevcache = { } + -- read interface information local n, i for n, i in ipairs(nxo.getifaddrs()) do @@ -375,7 +384,17 @@ function del_network(self, n) _uci_real:foreach("wireless", "wifi-iface", function(s) - if s.network == n then + local net + local rest = { } + for net in utl.imatch(s.network) do + if net ~= n then + rest[#rest+1] = net + end + end + if #rest > 0 then + _uci_real:set("wireless", s['.name'], "network", + table.concat(rest, " ")) + else _uci_real:delete("wireless", s['.name'], "network") end end) @@ -412,8 +431,18 @@ function rename_network(self, old, new) _uci_real:foreach("wireless", "wifi-iface", function(s) - if s.network == old then - _uci_real:set("wireless", s['.name'], "network", new) + local net + local list = { } + for net in utl.imatch(s.network) do + if net == old then + list[#list+1] = new + else + list[#list+1] = net + end + end + if #list > 0 then + _uci_real:set("wireless", s['.name'], "network", + table.concat(list, " ")) end end) @@ -576,6 +605,44 @@ function del_wifinet(self, net) return false end +function get_status_by_route(self, addr, mask) + local _, object + for _, object in ipairs(_ubus:objects()) do + local net = object:match("^network%.interface%.(.+)") + if net then + local s = _ubus:call(object, "status", {}) + if s and s.route then + local rt + for _, rt in ipairs(s.route) do + if rt.target == addr and rt.mask == mask then + return net, s + end + end + end + end + end +end + +function get_wannet(self) + local net = self:get_status_by_route("0.0.0.0", 0) + return net and network(net) +end + +function get_wandev(self) + local _, stat = self:get_status_by_route("0.0.0.0", 0) + return stat and interface(stat.l3_device or stat.device) +end + +function get_wan6net(self) + local net = self:get_status_by_route("::", 0) + return net and network(net) +end + +function get_wan6dev(self) + local _, stat = self:get_status_by_route("::", 0) + return stat and interface(stat.l3_device or stat.device) +end + function network(name, proto) if name then @@ -597,22 +664,15 @@ function protocol._get(self, opt) return v or "" end -function protocol._ip(self, opt, family, list) - local ip = _uci_state:get("network", self.sid, opt) - local fc = (family == 6) and ipc.IPv6 or ipc.IPv4 - if ip or list then - if list then - local l = { } - for ip in utl.imatch(ip) do - ip = fc(ip) - if ip then l[#l+1] = ip:string() end - end - return l - else - ip = fc(ip) - return ip and ip:string() - end +function protocol._ubus(self, field) + if not _ubusnetcache[self.sid] then + _ubusnetcache[self.sid] = _ubus:call("network.interface.%s" % self.sid, + "status", { }) + end + if _ubusnetcache[self.sid] and field then + return _ubusnetcache[self.sid][field] end + return _ubusnetcache[self.sid] end function protocol.get(self, opt) @@ -624,36 +684,31 @@ function protocol.set(self, opt, val) end function protocol.ifname(self) - local p = self:proto() - if self:is_bridge() then - return "br-" .. self.sid - elseif self:is_virtual() then - return p .. "-" .. self.sid + local ifname + if self:is_floating() then + ifname = self:_ubus("l3_device") else + ifname = self:_ubus("device") + end + if not ifname then local num = { } - local dev = _uci_real:get("network", self.sid, "ifname") or - _uci_state:get("network", self.sid, "ifname") - - dev = (type(dev) == "table") and dev[1] or dev - dev = (dev ~= nil) and dev:match("%S+") - - if not dev then - _uci_real:foreach("wireless", "wifi-iface", - function(s) - if s.device then - num[s.device] = num[s.device] - and num[s.device] + 1 or 1 + _uci_real:foreach("wireless", "wifi-iface", + function(s) + if s.device then + num[s.device] = num[s.device] + and num[s.device] + 1 or 1 - if s.network == self.sid then - dev = "%s.network%d" %{ s.device, num[s.device] } + local net + for net in utl.imatch(s.network) do + if net == self.sid then + ifname = "%s.network%d" %{ s.device, num[s.device] } return false end end - end) - end - - return dev + end + end) end + return ifname end function protocol.proto(self) @@ -663,13 +718,13 @@ end function protocol.get_i18n(self) local p = self:proto() if p == "none" then - return i18n.translate("Unmanaged") + return lng.translate("Unmanaged") elseif p == "static" then - return i18n.translate("Static address") + return lng.translate("Static address") elseif p == "dhcp" then - return i18n.translate("DHCP client") + return lng.translate("DHCP client") else - return i18n.translate("Unknown") + return lng.translate("Unknown") end end @@ -682,12 +737,7 @@ function protocol.name(self) end function protocol.uptime(self) - local cnt = tonumber(_uci_state:get("network", self.sid, "connect_time")) - if cnt ~= nil then - return nxo.sysinfo().uptime - cnt - else - return 0 - end + return self:_ubus("uptime") or 0 end function protocol.expires(self) @@ -705,51 +755,60 @@ function protocol.metric(self) end function protocol.ipaddr(self) - return self:_ip("ipaddr", 4) + local addrs = self:_ubus("ipv4-address") + return addrs and #addrs > 0 and addrs[1].address end function protocol.netmask(self) - return self:_ip("netmask", 4) + local addrs = self:_ubus("ipv4-address") + return addrs and #addrs > 0 and + ipc.IPv4("0.0.0.0/%d" % addrs[1].mask):mask():string() end function protocol.gwaddr(self) - return self:_ip("gateway", 4) + local _, route + for _, route in ipairs(self:_ubus("route") or { }) do + if route.target == "0.0.0.0" and route.mask == 0 then + return route.nexthop + end + end end function protocol.dnsaddrs(self) - return self:_ip("dns", 4, true) + local dns = { } + local _, addr + for _, addr in ipairs(self:_ubus("dns-server") or { }) do + if not addr:match(":") then + dns[#dns+1] = addr + end + end + return dns end function protocol.ip6addr(self) - local ip6 = self:_ip("ip6addr", 6) - if not ip6 then - local ifc = _interfaces[self:ifname()] - if ifc and ifc.ip6addrs then - local a - for _, a in ipairs(ifc.ip6addrs) do - if not a:is6linklocal() then - ip6 = a:string() - break - end - end - end - end - return ip6 + local addrs = self:_ubus("ipv6-address") + return addrs and #addrs > 0 + and "%s/%d" %{ addrs[1].address, addrs[1].mask } end function protocol.gw6addr(self) - local ip6 = self:_ip("ip6gw", 6) - if not ip6 then - local dr6 = sys.net.defaultroute6() - if dr6 and dr6.device == self:ifname() then - return dr6.nexthop:string() + local _, route + for _, route in ipairs(self:_ubus("route") or { }) do + if route.target == "::" and route.mask == 0 then + return ipc.IPv6(route.nexthop):string() end end - return ip6 end function protocol.dns6addrs(self) - return self:_ip("dns", 6, true) + local dns = { } + local _, addr + for _, addr in ipairs(self:_ubus("dns-server") or { }) do + if addr:match(":") then + dns[#dns+1] = addr + end + end + return dns end function protocol.is_bridge(self) @@ -784,9 +843,12 @@ function protocol.is_empty(self) _uci_real:foreach("wireless", "wifi-iface", function(s) - if s.network == self.sid then - rv = false - return false + local n + for n in utl.imatch(s.network) do + if n == self.sid then + rv = false + return false + end end end) @@ -797,16 +859,10 @@ end function protocol.add_interface(self, ifname) ifname = _M:ifnameof(ifname) if ifname and not self:is_floating() then - -- remove the interface from all ifaces - _uci_real:foreach("network", "interface", - function(s) - _filter("network", s['.name'], "ifname", ifname) - end) - -- if its a wifi interface, change its network option local wif = _wifi_lookup(ifname) if wif then - _uci_real:set("wireless", wif, "network", self.sid) + _append("wireless", wif, "network", self.sid) -- add iface to our iface list else @@ -820,7 +876,7 @@ function protocol.del_interface(self, ifname) if ifname and not self:is_floating() then -- if its a wireless interface, clear its network option local wif = _wifi_lookup(ifname) - if wif then _uci_real:delete("wireless", wif, "network") end + if wif then _filter("wireless", wif, "network", self.sid) end -- remove the interface _filter("network", self.sid, "ifname", ifname) @@ -846,9 +902,13 @@ function protocol.get_interface(self) function(s) if s.device then num[s.device] = num[s.device] and num[s.device] + 1 or 1 - if s.network == self.sid then - ifn = s.ifname or "%s.network%d" %{ s.device, num[s.device] } - return false + + local net + for net in utl.imatch(s.network) do + if net == self.sid then + ifn = "%s.network%d" %{ s.device, num[s.device] } + return false + end end end end) @@ -877,9 +937,13 @@ function protocol.get_interfaces(self) function(s) if s.device then num[s.device] = num[s.device] and num[s.device] + 1 or 1 - if s.network == self.sid then - ifn = "%s.network%d" %{ s.device, num[s.device] } - wfs[ifn] = interface(ifn, self) + + local net + for net in utl.imatch(s.network) do + if net == self.sid then + ifn = "%s.network%d" %{ s.device, num[s.device] } + wfs[ifn] = interface(ifn, self) + end end end end) @@ -911,7 +975,12 @@ function protocol.contains_interface(self, ifname) local wif = _wifi_lookup(ifname) if wif then - return (_uci_real:get("wireless", wif, "network") == self.sid) + local n + for n in utl.imatch(_uci_real:get("wireless", wif, "network")) do + if n == self.sid then + return true + end + end end end @@ -927,19 +996,33 @@ interface = utl.class() function interface.__init__(self, ifname, network) local wif = _wifi_lookup(ifname) - if wif then self.wif = wifinet(wif) end + if wif then + self.wif = wifinet(wif) + self.ifname = _uci_state:get("wireless", wif, "ifname") + end self.ifname = self.ifname or ifname self.dev = _interfaces[self.ifname] self.network = network end +function interface._ubus(self, field) + if not _ubusdevcache[self.ifname] then + _ubusdevcache[self.ifname] = _ubus:call("network.device", "status", + { name = self.ifname }) + end + if _ubusdevcache[self.ifname] and field then + return _ubusdevcache[self.ifname][field] + end + return _ubusdevcache[self.ifname] +end + function interface.name(self) return self.wif and self.wif:ifname() or self.ifname end function interface.mac(self) - return (self.dev and self.dev.macaddr or "00:00:00:00:00:00"):upper() + return (self:_ubus("macaddr") or "00:00:00:00:00:00"):upper() end function interface.ipaddrs(self) @@ -980,7 +1063,7 @@ end function interface.get_i18n(self) if self.wif then return "%s: %s %q" %{ - i18n.translate("Wireless Network"), + lng.translate("Wireless Network"), self.wif:active_mode(), self.wif:active_ssid() or self.wif:active_bssid() } @@ -992,17 +1075,17 @@ end function interface.get_type_i18n(self) local x = self:type() if x == "wifi" then - return i18n.translate("Wireless Adapter") + return lng.translate("Wireless Adapter") elseif x == "bridge" then - return i18n.translate("Bridge") + return lng.translate("Bridge") elseif x == "switch" then - return i18n.translate("Ethernet Switch") + return lng.translate("Ethernet Switch") elseif x == "vlan" then - return i18n.translate("VLAN Interface") + return lng.translate("VLAN Interface") elseif x == "tunnel" then - return i18n.translate("Tunnel Interface") + return lng.translate("Tunnel Interface") else - return i18n.translate("Ethernet Adapter") + return lng.translate("Ethernet Adapter") end end @@ -1013,13 +1096,13 @@ function interface.adminlink(self) end function interface.ports(self) - if self.br then - local iface + local members = self:_ubus("bridge-members") + if members then + local _, iface local ifaces = { } - for _, iface in ipairs(self.br.ifnames) do - ifaces[#ifaces+1] = interface(iface.name) + for _, iface in ipairs(members) do + ifaces[#ifaces+1] = interface(iface) end - return ifaces end end @@ -1043,7 +1126,7 @@ function interface.is_up(self) if self.wif then return self.wif:is_up() else - return self.dev and self.dev.flags and self.dev.flags.up or false + return self:_ubus("up") or false end end @@ -1055,45 +1138,53 @@ function interface.is_bridgeport(self) return self.dev and self.dev.bridge and true or false end +local function uint(x) + if x then + return (x < 0) and ((2^32) + x) or x + end + return 0 +end + function interface.tx_bytes(self) - return self.dev and self.dev.stats - and self.dev.stats.tx_bytes or 0 + local stat = self:_ubus("statistics") + return stat and uint(stat.tx_bytes) or 0 end function interface.rx_bytes(self) - return self.dev and self.dev.stats - and self.dev.stats.rx_bytes or 0 + local stat = self:_ubus("statistics") + return stat and uint(stat.rx_bytes) or 0 end function interface.tx_packets(self) - return self.dev and self.dev.stats - and self.dev.stats.tx_packets or 0 + local stat = self:_ubus("statistics") + return stat and uint(stat.tx_packets) or 0 end function interface.rx_packets(self) - return self.dev and self.dev.stats - and self.dev.stats.rx_packets or 0 + local stat = self:_ubus("statistics") + return stat and uint(stat.rx_packets) or 0 end function interface.get_network(self) - if not self.network then - if self.dev and self.dev.network then - self.network = _M:get_network(self.dev.network) - end - end + return self:get_networks()[1] +end - if not self.network then - local net +function interface.get_networks(self) + if not self.networks then + local nets = { } + local _, net for _, net in ipairs(_M:get_networks()) do if net:contains_interface(self.ifname) or net:ifname() == self.ifname then - self.network = net - return net + nets[#nets+1] = net end end + table.sort(nets, function(a, b) return a.sid < b.sid end) + self.networks = nets + return nets else - return self.network + return self.networks end end @@ -1305,7 +1396,7 @@ function wifinet.active_mode(self) end function wifinet.active_mode_i18n(self) - return i18n.translate(self:active_mode()) + return lng.translate(self:active_mode()) end function wifinet.active_ssid(self) @@ -1357,7 +1448,12 @@ function wifinet.country(self) end function wifinet.txpower(self) - return self.iwinfo.txpower or 0 + local pwr = (self.iwinfo.txpower or 0) + return pwr + self:txpower_offset() +end + +function wifinet.txpower_offset(self) + return self.iwinfo.txpower_offset or 0 end function wifinet.signal_level(self, s, n) @@ -1389,15 +1485,15 @@ end function wifinet.shortname(self) return "%s %q" %{ - i18n.translate(self:active_mode()), + lng.translate(self:active_mode()), self:active_ssid() or self:active_bssid() } end function wifinet.get_i18n(self) return "%s: %s %q (%s)" %{ - i18n.translate("Wireless Network"), - i18n.translate(self:active_mode()), + lng.translate("Wireless Network"), + lng.translate(self:active_mode()), self:active_ssid() or self:active_bssid(), self:ifname() } @@ -1408,9 +1504,19 @@ function wifinet.adminlink(self) end function wifinet.get_network(self) - if _uci_real:get("network", self.iwdata.network) == "interface" then - return network(self.iwdata.network) + return self:get_networks()[1] +end + +function wifinet.get_networks(self) + local nets = { } + local net + for net in utl.imatch(tostring(self.iwdata.network)) do + if _uci_real:get("network", net) == "interface" then + nets[#nets+1] = network(net) + end end + table.sort(nets, function(a, b) return a.sid < b.sid end) + return nets end function wifinet.get_interface(self)