X-Git-Url: http://git.openwrt.org/?p=project%2Fluci.git;a=blobdiff_plain;f=libs%2Fcore%2Fluasrc%2Fmodel%2Fnetwork.lua;h=5e7d7d6b6f1fb00bbabec1f0c131cc792ed97b47;hp=cc4200cb48378c55383d5f63ccbe2d81e1775007;hb=a6dcb3f6a3af704b6331e2fe789e57f692bf9c7f;hpb=b30437329760a0dc2a92a41172802986e499a148 diff --git a/libs/core/luasrc/model/network.lua b/libs/core/luasrc/model/network.lua index cc4200cb48..5e7d7d6b6f 100644 --- a/libs/core/luasrc/model/network.lua +++ b/libs/core/luasrc/model/network.lua @@ -17,8 +17,8 @@ limitations under the License. ]]-- -local type, pairs, ipairs, loadfile, table, tonumber, math, i18n - = type, pairs, ipairs, loadfile, table, tonumber, math, luci.i18n +local type, next, pairs, ipairs, loadfile, table, tonumber, math, i18n + = type, next, pairs, ipairs, loadfile, table, tonumber, math, luci.i18n local nxo = require "nixio" local ipc = require "luci.ip" @@ -30,7 +30,7 @@ local uci = require "luci.model.uci" module "luci.model.network" -local ifs, brs, sws, uci_r, uci_s +local ifs, brs, sws, tns, uci_r, uci_s function _list_del(c, s, o, r) local val = uci_r:get(c, s, o) @@ -150,12 +150,19 @@ function _wifi_lookup(ifn) end end +function _iface_virtual(x) + return ( + x:match("^6in4-%w") or x:match("^6to4-%w") or x:match("^3g-%w") or + x:match("^ppp-%w") or x:match("^pppoe-%w") or x:match("^pppoa-%w") or + x:match("^relay-%w") + ) +end + function _iface_ignore(x) return ( x:match("^wmaster%d") or x:match("^wifi%d") or x:match("^hwsim%d") or - x:match("^imq%d") or x:match("^mon.wlan%d") or x:match("^6in4-%w") or - x:match("^6to4-%w") or x:match("^3g-%w") or x:match("^ppp-%w") or - x:match("^pppoe-%w") or x:match("^pppoa-%w") or x == "lo" + x:match("^imq%d") or x:match("^mon.wlan%d") or + x == "sit0" or x == "lo" or _iface_virtual(x) ) end @@ -167,6 +174,7 @@ function init(cursor) ifs = { } brs = { } sws = { } + tns = { } -- read interface information local n, i @@ -174,7 +182,11 @@ function init(cursor) local name = i.name:match("[^:]+") local prnt = name:match("^([^%.]+)%.") - if not _iface_ignore(name) then + if _iface_virtual(name) then + tns[name] = true + end + + if tns[name] or not _iface_ignore(name) then ifs[name] = ifs[name] or { idx = i.ifindex or n, name = name, @@ -242,10 +254,19 @@ function has_ipv6(self) 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 + local oldnet = self:get_network(n) + if n and #n > 0 and n:match("^[a-zA-Z0-9_]+$") and not oldnet then if uci_r:section("network", "interface", n, options) then return network(n) end + elseif oldnet and oldnet:is_empty() then + if options then + local k, v + for k, v in pairs(options) do + oldnet:set(k, v) + end + end + return oldnet end end @@ -378,6 +399,24 @@ function get_interfaces(self) end end + -- find vlan interfaces + uci_r:foreach("network", "switch_vlan", + function(s) + local base = s.device or "-" + if not base:match("^eth%d") then + base = "eth0" + end + + local vid = tonumber(s.vid or s.vlan) + if vid ~= nil and vid >= 0 and vid <= 4095 then + local iface = "%s.%d" %{ base, vid } + if not seen[iface] then + seen[iface] = true + nfs[iface] = interface(iface) + end + end + end) + for iface in utl.kspairs(nfs) do ifaces[#ifaces+1] = nfs[iface] end @@ -466,6 +505,24 @@ function network._get(self, opt) return v or "" end +function network._ip(self, opt, family, list) + local ip = uci_s: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 + end +end + function network.get(self, opt) return _get("network", self.sid, opt) end @@ -478,13 +535,17 @@ function network.ifname(self) local p = self:proto() if self:is_bridge() then return "br-" .. self.sid + elseif self:proto() == "relay" then + return uci_s:get("network", self.sid, "up") == "1" and "lo" or nil elseif self:is_virtual() then return p .. "-" .. self.sid else - local dev = self:_get("ifname") or - uci_r:get("network", self.sid, "ifname") + local num = { } + local dev = uci_r:get("network", self.sid, "ifname") or + uci_s:get("network", self.sid, "ifname") - dev = dev and dev:match("%S+") + dev = (type(dev) == "table") and dev[1] or dev + dev = (dev ~= nil) and dev:match("%S+") if not dev then uci_r:foreach("wireless", "wifi-iface", @@ -506,11 +567,21 @@ function network.ifname(self) end function network.device(self) - local dev = self:_get("device") + local dev = uci_r:get("network", self.sid, "device") or + uci_s:get("network", self.sid, "device") + + dev = (type(dev) == "table") and dev[1] or dev + if not dev or dev:match("[^%w%-%.%s]") then - dev = uci_r:get("network", self.sid, "ifname") + dev = uci_r:get("network", self.sid, "ifname") or + uci_s:get("network", self.sid, "ifname") + + dev = (type(dev) == "table") and dev[1] or dev + end + + for dev in utl.imatch(dev) do + return dev end - return dev end function network.proto(self) @@ -525,6 +596,77 @@ function network.name(self) return self.sid end +function network.uptime(self) + local cnt = tonumber(uci_s:get("network", self.sid, "connect_time")) + if cnt ~= nil then + return nxo.sysinfo().uptime - cnt + else + return 0 + end +end + +function network.expires(self) + local a = tonumber(uci_s:get("network", self.sid, "lease_acquired")) + local l = tonumber(uci_s:get("network", self.sid, "lease_lifetime")) + if a and l then + l = l - (nxo.sysinfo().uptime - a) + return l > 0 and l or 0 + end + return -1 +end + +function network.metric(self) + return tonumber(uci_s:get("network", self.sid, "metric")) or 0 +end + +function network.ipaddr(self) + return self:_ip("ipaddr", 4) +end + +function network.netmask(self) + return self:_ip("netmask", 4) +end + +function network.gwaddr(self) + return self:_ip("gateway", 4) +end + +function network.dnsaddrs(self) + return self:_ip("dns", 4, true) +end + +function network.ip6addr(self) + local ip6 = self:_ip("ip6addr", 6) + if not ip6 then + local ifc = ifs[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 +end + +function network.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() + end + end + return ip6 +end + +function network.dns6addrs(self) + return self:_ip("dns", 6, true) +end + function network.is_bridge(self) return (self:type() == "bridge") end @@ -533,10 +675,14 @@ function network.is_virtual(self) local p = self:proto() return ( p == "3g" or p == "6in4" or p == "6to4" or p == "ppp" or - p == "pppoe" or p == "pppoa" + p == "pppoe" or p == "pppoa" or p == "relay" ) end +function network.is_floating(self) + return (self:is_virtual() and self:proto() ~= "pppoe") +end + function network.is_empty(self) if self:is_virtual() then return false @@ -560,7 +706,7 @@ function network.is_empty(self) end function network.add_interface(self, ifname) - if not self:is_virtual() then + if not self:is_floating() then if type(ifname) ~= "string" then ifname = ifname:name() else @@ -586,7 +732,7 @@ function network.add_interface(self, ifname) end function network.del_interface(self, ifname) - if not self:is_virtual() then + if not self:is_floating() then if utl.instanceof(ifname, interface) then ifname = ifname:name() else @@ -602,18 +748,44 @@ function network.del_interface(self, ifname) end end -function network.get_interfaces(self) - local ifaces = { } - - local ifn +function network.get_interface(self) if self:is_virtual() then - ifn = self:proto() .. "-" .. self.sid - ifaces = { interface(ifn) } + tns[self:proto() .. "-" .. self.sid] = true + return interface(self:proto() .. "-" .. self.sid, self) + elseif self:is_bridge() then + brs["br-" .. self.sid] = true + return interface("br-" .. self.sid, self) else + local ifn = nil + local num = { } + for ifn in utl.imatch(uci_s:get("network", self.sid, "ifname")) do + ifn = ifn:match("^[^:/]+") + return ifn and interface(ifn, self) + end + ifn = nil + uci_s: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 + ifn = s.ifname or "%s.network%d" %{ s.device, num[s.device] } + return false + end + end + end) + return ifn and interface(ifn, self) + end +end + +function network.get_interfaces(self) + if self:is_bridge() or (self:is_virtual() and not self:is_floating()) then + local ifaces = { } + + local ifn local nfs = { } for ifn in utl.imatch(self:get("ifname")) do - ifn = ifn:match("[^:]+") - nfs[ifn] = interface(ifn) + ifn = ifn:match("^[^:/]+") + nfs[ifn] = interface(ifn, self) end for ifn in utl.kspairs(nfs) do @@ -628,7 +800,7 @@ function network.get_interfaces(self) 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) + wfs[ifn] = interface(ifn, self) end end end) @@ -636,9 +808,9 @@ function network.get_interfaces(self) for ifn in utl.kspairs(wfs) do ifaces[#ifaces+1] = wfs[ifn] end - end - return ifaces + return ifaces + end end function network.contains_interface(self, ifname) @@ -648,11 +820,12 @@ function network.contains_interface(self, ifname) ifname = ifname:match("[^%s:]+") end - local ifn - if self:is_virtual() then - ifn = self:proto() .. "-" .. self.sid - return ifname == ifn + if self:is_virtual() and self:proto() .. "-" .. self.sid == ifname then + return true + elseif self:is_bridge() and "br-" .. self.sid == ifname then + return true else + local ifn for ifn in utl.imatch(self:get("ifname")) do ifn = ifn:match("[^:]+") if ifn == ifname then @@ -675,12 +848,13 @@ end interface = utl.class() -function interface.__init__(self, ifname) +function interface.__init__(self, ifname, network) local wif = _wifi_lookup(ifname) if wif then self.wif = wifinet(wif) end - self.ifname = self.ifname or ifname - self.dev = ifs[self.ifname] + self.ifname = self.ifname or ifname + self.dev = ifs[self.ifname] + self.network = network end function interface.name(self) @@ -688,7 +862,7 @@ function interface.name(self) end function interface.mac(self) - return self.dev and self.dev.macaddr or "00:00:00:00:00:00" + return (self.dev and self.dev.macaddr or "00:00:00:00:00:00"):upper() end function interface.ipaddrs(self) @@ -704,7 +878,11 @@ function interface.type(self) return "wifi" elseif brs[self.ifname] then return "bridge" - elseif sws[self.ifname] or self.ifname:match("%.") then + elseif tns[self.ifname] then + return "tunnel" + elseif self.ifname:match("%.") then + return "vlan" + elseif sws[self.ifname] then return "switch" else return "ethernet" @@ -742,6 +920,10 @@ function interface.get_type_i18n(self) return i18n.translate("Bridge") elseif x == "switch" then return i18n.translate("Ethernet Switch") + elseif x == "vlan" then + return i18n.translate("VLAN Interface") + elseif x == "tunnel" then + return i18n.translate("Tunnel Interface") else return i18n.translate("Ethernet Adapter") end @@ -817,14 +999,18 @@ function interface.rx_packets(self) end function interface.get_network(self) - if self.dev and self.dev.network then - self.network = _M:get_network(self.dev.network) + if not self.network then + if self.dev and self.dev.network then + self.network = _M:get_network(self.dev.network) + end end if not self.network then local net for _, net in ipairs(_M:get_networks()) do - if net:contains_interface(self.ifname) then + if net:contains_interface(self.ifname) or + net:ifname() == self.ifname + then self.network = net return net end @@ -841,7 +1027,8 @@ end wifidev = utl.class() function wifidev.__init__(self, dev) - self.sid = dev + self.sid = dev + self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { } end function wifidev.get(self, opt) @@ -856,6 +1043,33 @@ function wifidev.name(self) return self.sid end +function wifidev.hwmodes(self) + local l = self.iwinfo.hwmodelist + if l and next(l) then + return l + else + return { b = true, g = true } + end +end + +function wifidev.get_i18n(self) + local t = "Generic" + if self.iwinfo.type == "wl" then + t = "Broadcom" + elseif self.iwinfo.type == "madwifi" then + t = "Atheros" + end + + local m = "" + local l = self:hwmodes() + if l.a then m = m .. "a" end + if l.b then m = m .. "b" end + if l.g then m = m .. "g" end + if l.n then m = m .. "n" end + + return "%s 802.11%s Wireless Controller (%s)" %{ t, m, self:name() } +end + function wifidev.is_up(self) local up = false @@ -926,21 +1140,22 @@ wifinet = utl.class() function wifinet.__init__(self, net, data) self.sid = net - local dev = uci_s:get("wireless", self.sid, "ifname") - if not dev then - local num = { } - uci_r: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['.name'] == self.sid then - dev = "%s.network%d" %{ s.device, num[s.device] } - return false - end + local num = { } + local netid + uci_r: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['.name'] == self.sid then + netid = "%s.network%d" %{ s.device, num[s.device] } + return false end - end) - end + end + end) + local dev = uci_s:get("wireless", self.sid, "ifname") or netid + + self.netid = netid self.wdev = dev self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { } self.iwdata = data or uci_s:get_all("wireless", self.sid) or @@ -971,6 +1186,10 @@ function wifinet.network(self) return uci_s:get("wifinet", self.sid, "network") end +function wifinet.id(self) + return self.netid +end + function wifinet.name(self) return self.sid end @@ -996,7 +1215,7 @@ end function wifinet.active_mode(self) local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap" - if m == "ap" then m = "AP" + if m == "ap" then m = "Master" elseif m == "sta" then m = "Client" elseif m == "adhoc" then m = "Ad-Hoc" elseif m == "mesh" then m = "Mesh" @@ -1054,6 +1273,14 @@ function wifinet.noise(self) return self.iwinfo.noise or 0 end +function wifinet.country(self) + return self.iwinfo.country or "00" +end + +function wifinet.txpower(self) + return self.iwinfo.txpower or 0 +end + function wifinet.signal_level(self, s, n) if self:active_bssid() ~= "00:00:00:00:00:00" then local signal = s or self:signal() @@ -1098,8 +1325,7 @@ function wifinet.get_i18n(self) end function wifinet.adminlink(self) - return dsp.build_url("admin", "network", "wireless", - self.iwdata.device, self.wdev) + return dsp.build_url("admin", "network", "wireless", self.netid) end function wifinet.get_network(self)