diff options
-rw-r--r-- | contrib/package/luci/Makefile | 19 | ||||
-rw-r--r-- | libs/core/luasrc/model/network.lua | 895 | ||||
-rw-r--r-- | libs/core/luasrc/model/uci.lua (renamed from libs/uci/luasrc/model/uci.lua) | 0 | ||||
-rw-r--r-- | libs/core/luasrc/model/uci/bind.lua (renamed from libs/uci/luasrc/model/uci/bind.lua) | 0 | ||||
-rw-r--r-- | libs/core/root/etc/config/ucitrack (renamed from libs/uci/root/etc/config/ucitrack) | 0 | ||||
-rwxr-xr-x | libs/core/root/sbin/luci-reload (renamed from libs/uci/root/sbin/luci-reload) | 0 |
6 files changed, 897 insertions, 17 deletions
diff --git a/contrib/package/luci/Makefile b/contrib/package/luci/Makefile index 70c76486aa..4099e5148d 100644 --- a/contrib/package/luci/Makefile +++ b/contrib/package/luci/Makefile @@ -158,17 +158,6 @@ endif ### Libraries ### -define Package/luci-uci - $(call Package/luci/libtemplate) - DEPENDS+=+libuci-lua - TITLE:=High-Level UCI API -endef - -define Package/luci-uci/install - $(call Package/luci/install/template,$(1),libs/uci) -endef - - define Package/luci-fastindex $(call Package/luci/libtemplate) TITLE:=Fastindex indexing module @@ -315,7 +304,7 @@ endef define Package/luci-web $(call Package/luci/libtemplate) - DEPENDS+=+luci-sys +luci-nixio +luci-uci \ + DEPENDS+=+luci-sys +luci-nixio +luci-core \ +luci-sgi-cgi +luci-lmo TITLE:=MVC Webframework $(call Config,luci.main.lang,string,auto,Default Language) @@ -332,7 +321,7 @@ endef define Package/luci-uvl $(call Package/luci/libtemplate) - DEPENDS+=+luci-sys +luci-uci +luci-core + DEPENDS+=+luci-sys +luci-core TITLE:=UVL - UCI Validation Layer endef @@ -1075,9 +1064,6 @@ endif ifneq ($(CONFIG_PACKAGE_luci-px5g),) PKG_SELECTED_MODULES+=libs/px5g endif -ifneq ($(CONFIG_PACKAGE_luci-uci),) - PKG_SELECTED_MODULES+=libs/uci -endif ifneq ($(CONFIG_PACKAGE_luci-sys),) PKG_SELECTED_MODULES+=libs/sys endif @@ -1292,7 +1278,6 @@ $(eval $(call BuildPackage,luci-luanet)) $(eval $(call BuildPackage,luci-lucid)) $(eval $(call BuildPackage,luci-nixio)) $(eval $(call BuildPackage,luci-px5g)) -$(eval $(call BuildPackage,luci-uci)) $(eval $(call BuildPackage,luci-sys)) $(eval $(call BuildPackage,luci-web)) $(eval $(call BuildPackage,luci-uvl)) diff --git a/libs/core/luasrc/model/network.lua b/libs/core/luasrc/model/network.lua index 8459463f13..53649dde55 100644 --- a/libs/core/luasrc/model/network.lua +++ b/libs/core/luasrc/model/network.lua @@ -483,3 +483,898 @@ function interface.get_network(self) end end +--[==[ +#!/usr/bin/lua + +local uci = require "luci.model.uci".cursor_state() +local utl = require "luci.util" +local sys = require "luci.sys" +local lip = require "luci.ip" +local nxo = require "nixio" +local nfs = require "nixio.fs" + +-- patch uci +local x = getmetatable(uci) + +function x:list(...) + local val = self:get(...) + local lst = { } + + if type(val) == "list" then + local _, v + for _, v in ipairs(val) do + local i + for i in v:gmatch("%S+") do + lst[#lst+1] = i + end + end + elseif type(val) == "string" then + local i + for i in val:gmatch("%S+") do + lst[#lst+1] = i + end + end + + return lst +end + + +system = utl.class() + +system._switches = { } +system._vlans = { } + +function system:__init__() + self._networks = { } + + uci:foreach("network2", "interface", + function(s) + self._networks[#self._networks+1] = system.network(s, self) + end) +end + +function system:networks() + local index = 0 + return function() + if index <= #self._networks then + index = index + 1 + return self._networks[index] + else + return nil + end + end +end + +function system:find_network(name) + local v + for _, v in ipairs(self._networks) do + if v:name() == name then + return v + end + end +end + +function system:find_interface(name) + local v + for _, v in ipairs(self._networks) do + local i + for i in v:interfaces() do + if i:is_bridge() then + local p + for p in i:interfaces() do + if p:name() == name then + return p + end + end + end + + if i:name() == name then + return i + end + end + end +end + +function system:delete_network(name) + local i + for i = 1, #self._networks do + if self._networks[i]:name() == name then + local x + + for x in self._networks[i]:aliases() do + uci:delete("network2", x:name()) + end + + for x in self._networks[i]:routes() do + uci:delete("network2", x:name()) + end + + uci:delete("network2", self._networks[i]) + table.remove(self._networks, i) + + return true + end + end + return false +end + +function system:print() + local v + for v in self:networks() do + print(v:name()) + v:print() + print("--") + end +end + +function system.ignore_iface(ifn) + return (nil ~= ( + ifn:match("^wlan%d") or + ifn:match("^ath%d") or + ifn:match("^wl%d") or + ifn:match("^imq%d") or + ifn:match("^br%-") or + ifn:match("^/dev/") + )) +end + +function system.find_wifi_networks(net) + local lst = { } + local cnt = 0 + + uci:foreach("wireless", "wifi-iface", + function(s) + if s.device and s.network == net then + lst[#lst+1] = { s.device, s['.name'], cnt } + end + cnt = cnt + 1 + end) + + return lst +end + +function system.find_iface_names(net) + local lst = { } + + local val = uci:list("network2", net, "device") + if #val == 0 or val[1]:match("^/dev/") then + val = uci:list("network2", net, "ifname") + end + + local ifn + for _, ifn in ipairs(val) do + if not system.ignore_iface(ifn) then + lst[#lst+1] = ifn + end + end + + return lst +end + +function system.find_switch(name) + local swname, swdev, swvlan + + -- find switch + uci:foreach("network2", "switch", + function(s) + swname = s.name or s['.name'] + + -- special: rtl8366s is eth0 (wan is eth1) + if swname == "rtl8366s" then + swdev = "eth0" + + -- special: rtl8366rb is eth0 (wan + lan) + elseif swname == "rtl8366rb" then + swdev = "eth0" + + -- treat swname as swdev + else + swdev = swname + end + + return false + end) + + -- find first vlan + if swdev then + uci:foreach("network2", "switch_vlan", + function(s) + if s.device == swname then + local vlan = tonumber(s.vlan) + if vlan and (not swvlan or vlan < swvlan) then + swvlan = vlan + end + end + end) + end + + + local veth, vlan = name:match("^(%S+)%.(%d+)$") + + -- have vlan id and matching switch + if vlan and veth == swdev then + return swname, swdev, vlan + + -- have no vlan id but matching switch, assume first switch vlan + elseif not vlan and name == swdev then + return swname, swdev, swvlan + + -- have vlan and no matching switch, assume software vlan + elseif vlan then + return nil, veth, vlan + end +end + + +system.network = utl.class() + +function system.network:__init__(s, sys) + self._name = s['.name'] + self._sys = sys + self._routes = { } + self._aliases = { } + + if s.type == "bridge" then + self._interfaces = { system.network.bridge(s['.name'], self) } + else + self._interfaces = { } + + local ifn + + -- find wired ifaces + for _, ifn in ipairs(system.find_iface_names(self._name)) do + self._interfaces[#self._interfaces+1] = system.network.iface(ifn, self) + end + + -- find wifi networks + for _, ifn in ipairs(system.find_wifi_networks(self._name)) do + self._interfaces[#self._interfaces+1] = system.network.iface(ifn, self) + end + end + + -- find ipv4 routes + uci:foreach("network2", "route", + function(s) + if s.interface == self._name and s.target then + self._routes[#self._routes+1] = system.network.route(s, self) + end + end) + + -- find ipv6 routes + uci:foreach("network2", "route6", + function(s) + if s.interface == self._name and s.target then + self._routes[#self._routes+1] = system.network.route(s, self) + end + end) + + -- find aliases + uci:foreach("network2", "alias", + function(s) + if s.interface == self._name and s.proto then + self._aliases[#self._aliases+1] = system.network.alias(s, self) + end + end) +end + +function system.network:name() + return self._name +end + +function system.network:system() + return self._sys +end + +function system.network:interfaces() + local index = 0 + return function() + if index <= #self._interfaces then + index = index + 1 + return self._interfaces[index] + else + return nil + end + end +end + +function system.network:interface() + return self._interfaces[1] +end + +function system.network:num_routes() + return #self._routes +end + +function system.network:routes() + local index = 0 + return function() + if index <= #self._routes then + index = index + 1 + return self._routes[index] + else + return nil + end + end +end + +function system.network:num_aliases() + return #self._aliases +end + +function system.network:aliases() + local index = 0 + return function() + if index <= #self._aliases then + index = index + 1 + return self._aliases[index] + else + return nil + end + end +end + +function system.network:delete_route(rt) + local i + for i = 1, #self._routes do + if self._routes[i]:name() == rt:name() then + uci:delete("network2", rt:name()) + table.remove(self._routes, i) + return true + end + end + return false +end + +function system.network:delete_alias(al) + local i + for i = 1, #self._aliases do + if self._aliases[i]:name() == al:name() then + uci:delete("network2", al:name()) + table.remove(self._aliases, i) + return true + end + end + return false +end + +function system.network:print() + self:interface():print() +end + + +system.network.iface = utl.class() + +function system.network.iface:__init__(ifn, net, parent) + self._net = net + self._parent = parent + + -- is a wifi iface + if type(ifn) == "table" then + local wifidev, network, index = unpack(ifn) + + self._name = "%s.%d" %{ wifidev, index } + self._wifidev = wifidev + self._wifinet = index + self._ifname = uci:get("wireless", network, "ifname") or self._name + + -- is a wired iface + else + self._name = ifn + self._ifname = ifn + + local switch, swdev, vlan = system.find_switch(self._ifname) + + if switch then + self._switch = system.switch(switch, swdev, self) + end + + if vlan then + self._vlan = system.vlan(vlan, self._switch, self) + end + end +end + +function system.network.iface:name() + return self._name +end + +function system.network.iface:parent() + return self._parent +end + +function system.network.iface:network() + return self._net +end + +function system.network.iface:is_managed() + return (self._net ~= nil) +end + +function system.network.iface:is_vlan() + return (self._vlan ~= nil) +end + +function system.network.iface:is_software_vlan() + return (not self._switch and self._vlan ~= nil) +end + +function system.network.iface:is_hardware_vlan() + return (self._switch ~= nil and self._vlan ~= nil) +end + +function system.network.iface:_sysfs(path, default) + path = "/sys/class/net/%s/%s" %{ self._ifname, path } + + local data = nfs.readfile(path) + + if type(default) == "number" then + return tonumber(data) or default + elseif data and #data > 0 then + return data and data:gsub("%s+$", "") or default + end + + return default +end + +function system.network.iface:rx_bytes() + return self:_sysfs("statistics/rx_bytes", 0) +end + +function system.network.iface:tx_bytes() + return self:_sysfs("statistics/tx_bytes", 0) +end + +function system.network.iface:rx_packets() + return self:_sysfs("statistics/rx_packets", 0) +end + +function system.network.iface:tx_packets() + return self:_sysfs("statistics/tx_packets", 0) +end + +function system.network.iface:macaddr() + return self:_sysfs("address") +end + +function system.network.iface:mtu() + return self:_sysfs("mtu", 1500) +end + +function system.network.iface:is_bridge() + return (self:_sysfs("bridge/max_age", 0) > 0) +end + +function system.network.iface:is_bridge_port() + return (self:_sysfs("brport/port_no", 0) > 0) +end + +function system.network.iface:delete() + if self._wifidev then + local cnt = 0 + uci:foreach("wireless", "wifi-iface", + function(s) + cnt = cnt + 1 + if s.device == self._wifidev and cnt == self._wifinet then + uci:delete("wireless", s['.name']) + return false + end + end) + end +end + +function system.network.iface:print() + if self._wifidev then + print(" wifi: ", self._wifidev, "net: ", self._wifinet) + else + print(" iface: ", self._name) + end + + print(" rx: ", self:rx_bytes(), self:rx_packets()) + print(" tx: ", self:tx_bytes(), self:tx_packets()) + print(" mtu: ", self:mtu()) + print(" mac: ", self:macaddr()) + print(" bridge? ", self:is_bridge()) + print(" port? ", self:is_bridge_port()) + print(" swvlan? ", self:is_software_vlan()) + print(" hwvlan? ", self:is_hardware_vlan()) + + if self._switch then + self._switch:print() + end + + if self._vlan then + self._vlan:print() + end +end + + +system.network.bridge = utl.class(system.network.iface) + +function system.network.bridge:__init__(brn, net) + self._net = net + self._name = "br-" .. brn + self._ifname = self._name + self._interfaces = { } + + local ifn + + -- find wired ifaces + for _, ifn in ipairs(system.find_iface_names(brn)) do + self._interfaces[#self._interfaces+1] = system.network.iface(ifn, net, self) + end + + -- find wifi networks + for _, ifn in ipairs(system.find_wifi_networks(brn)) do + self._interfaces[#self._interfaces+1] = system.network.iface(ifn, net, self) + end +end + +function system.network.bridge:interfaces() + local index = 0 + return function() + if index <= #self._interfaces then + index = index + 1 + return self._interfaces[index] + else + return nil + end + end +end + +function system.network.bridge:print() + local v + for v in self:interfaces() do + io.write(" port: ") + v:print() + end + print(" rx: ", self:rx_bytes(), self:rx_packets()) + print(" tx: ", self:tx_bytes(), self:tx_packets()) + print(" mtu: ", self:mtu()) + print(" mac: ", self:macaddr()) + print(" bridge? ", self:is_bridge()) + print(" port? ", self:is_bridge_port()) +end + + +system.network.route = utl.class() + +function system.network.route:__init__(rt, net) + self._net = net + self._name = rt['.name'] + self._ipv6 = (rt['.type'] == "route6") + self._mtu = tonumber(rt.mtu) or (net and net:interface():mtu() or 1500) + self._metric = tonumber(rt.metric) or 0 + + if self._ipv6 then + self._gateway = lip.IPv6(rt.gateway or "::") + self._target = lip.IPv6(rt.target or "::") + else + self._gateway = lip.IPv4(rt.gateway or "0.0.0.0") + self._target = lip.IPv4(rt.target or "0.0.0.0", rt.netmask or "0.0.0.0") + end +end + +function system.network.route:name() + return self._name +end + +function system.network.route:network() + return self._net +end + +function system.network.route:mtu() + return self._mtu +end + +function system.network.route:metric() + return self._metric +end + +function system.network.route:is_ipv4() + return not self._ipv6 +end + +function system.network.route:is_ipv6() + return self._ipv6 +end + +function system.network.route:target() + return self._target +end + +function system.network.route:gateway() + return self._gateway +end + + +system.network.alias = utl.class() + +function system.network.alias:__init__(a, net) + self._net = net + self._name = a['.name'] +end + + +system.switch = utl.class() + +function system.switch:__init__(switch, swdev, net) + self._name = switch + self._ifname = swdev + self._net = net + + if not system._switches[switch] then + local x = io.popen("swconfig dev %q help 2>/dev/null" % switch) + if x then + local desc = x:read("*l") + + if desc then + local name, num_ports, num_cpu, num_vlans = + desc:match("Switch %d: %S+%((.-)%), ports: (%d+) %(cpu @ (%d+)%), vlans: (%d+)") + + self._model = name + self._ports = tonumber(num_ports) + self._cpuport = tonumber(num_cpu) + self._vlans = tonumber(num_vlans) + end + + x:close() + + elseif nfs.access("/proc/switch/%s" % switch) then + self._model = self:_proc("driver", switch) + self._ports = self:_proc_count("port", 6) + self._vlans = self:_proc_count("vlan", 16) + end + + -- defaults + self._model = self._model or switch + self._ports = self._ports or 6 + self._vlans = self._vlans or 16 + self._cpuport = self._cpuport or 5 + + system._switches[switch] = self + else + self._model = system._switches[switch]._model + self._ports = system._switches[switch]._ports + self._vlans = system._switches[switch]._vlans + self._cpuport = system._switches[switch]._cpuport + end +end + +function system.switch:_proc(path, default) + local data = nfs.readfile("/proc/switch/%s/%s" %{ self._name, path }) + if data then + return data:gsub("%s+$", "") + end + return default +end + +function system.switch:_proc_count(path, default) + local cnt = 0 + for _ in nfs.dir("/proc/switch/%s/%s" %{ self._name, path }) do + cnt = cnt + 1 + end + return cnt > 0 and cnt or default +end + +function system.switch:name() + return self._name +end + +function system.switch:model() + return self._model +end + +function system.switch:num_possible_vlans() + return self._vlans +end + +function system.switch:num_active_vlans() + local cnt = 0 + uci:foreach("network2", "switch_vlan", + function(s) + if s.device == self._name then cnt = cnt + 1 end + end) + return cnt +end + +function system.switch:vlans() + local index = 0 + local vlans = { } + + uci:foreach("network2", "switch_vlan", + function(s) + if s.device == self._name and tonumber(s.vlan) then + vlans[#vlans+1] = tonumber(s.vlan) + end + end) + + return function() + if index <= #vlans then + index = index + 1 + return system.vlan(vlans[index], self) + else + return nil + end + end +end + +function system.switch:num_ports() + return self._ports +end + +function system.switch:delete_vlan(vlan) + local rv = false + + uci:foreach("network2", "switch_vlan", + function(s) + if s.device == self._name and tonumber(s.vlan) == vlan then + rv = true + uci:delete("network2", s['.name']) + + if system._vlans[s.device] and system._vlans[s.device][vlan] then + table.remove(system._vlans[s.device], vlan) + end + + return false + end + end) + + return rv +end + +function system.switch:print() + print("Switch:", self._model) + print(" Ports:", self._ports, "Cpu:", self._cpuport) + print(" Vlans:", self._vlans) +end + + +system.vlan = utl.class() + +function system.vlan:__init__(vlan, switch, iface) + self._vlan = vlan + self._switch = switch + self._iface = iface + + local swid = (switch and switch:name()) or (iface and iface:name()) or "" + + if not system._vlans[swid] or not system._vlans[swid][vlan] then + self._ports = { } + + if switch then + uci:foreach("network2", "switch_vlan", + function(s) + if s.device == switch:name() and tonumber(s.vlan) == vlan then + local p + for _, p in ipairs(uci:list("network2", s['.name'], "ports")) do + self._ports[#self._ports+1] = system.vlan.port(p, self) + end + self._name = s['.name'] + end + end) + else + self._ports[#self._ports+1] = system.vlan.port("0t", self) + end + + system._vlans[swid] = system._vlans[swid] or { } + system._vlans[swid][vlan] = self + else + self._ports = system._vlans[swid][vlan]._ports + end +end + +function system.vlan:name() + return self._name +end + +function system.vlan:number() + return self._vlan +end + +function system.vlan:switch() + return self._switch +end + +function system.vlan:interface() + return self._iface +end + +function system.vlan:is_software() + return (self._switch == nil) +end + +function system.vlan:is_hardware() + return not self:is_software() +end + +function system.vlan:num_ports() + return #self._ports +end + +function system.vlan:ports() + local index = 0 + return function() + if index <= #self._ports then + index = index + 1 + return self._ports[index] + else + return nil + end + end +end + +function system.vlan:_update() + local i + local ports = { } + + for i = 1, #self._ports do + ports[#ports+1] = self._ports[i]:string() + end + + uci:set("network2", self._name, "ports", table.concat(ports, " ")) +end + +function system.vlan:delete_port(port) + if self._switch then + local i + for i = 1, #self._ports do + if self._ports[i]:number() == port then + table.remove(self._ports, i) + self:_update() + return true + end + end + end + return false +end + +function system.vlan:print() + print(" Vlan:", self._vlan, "Software?", self:is_software()) + local p + for p in self:ports() do + p:print() + end +end + + +system.vlan.port = utl.class() + +function system.vlan.port:__init__(port, vlan) + local num, tag = port:match("^(%d+)([tu]?)") + + self._vlan = vlan + self._port = tonumber(num) + self._tagged = (tag == "t") +end + +function system.vlan.port:number() + return self._port +end + +function system.vlan.port:vlan() + return self._vlan +end + +function system.vlan.port:string() + return "%i%s" %{ self._port, self._tagged ? "t" : "" } +end + +function system.vlan.port:is_tagged() + return self._tagged +end + +function system.vlan.port:print() + print(" Port:", self._port, "Tagged:", self._tagged) +end + + +-- ------------------------------ + +local s = system() + +s:print() + +s:find_network("wan"):print() +s:find_interface("eth0"):parent():print() + +]==] diff --git a/libs/uci/luasrc/model/uci.lua b/libs/core/luasrc/model/uci.lua index 66bd0a026e..66bd0a026e 100644 --- a/libs/uci/luasrc/model/uci.lua +++ b/libs/core/luasrc/model/uci.lua diff --git a/libs/uci/luasrc/model/uci/bind.lua b/libs/core/luasrc/model/uci/bind.lua index 9472dabebb..9472dabebb 100644 --- a/libs/uci/luasrc/model/uci/bind.lua +++ b/libs/core/luasrc/model/uci/bind.lua diff --git a/libs/uci/root/etc/config/ucitrack b/libs/core/root/etc/config/ucitrack index 7b47cc8d5b..7b47cc8d5b 100644 --- a/libs/uci/root/etc/config/ucitrack +++ b/libs/core/root/etc/config/ucitrack diff --git a/libs/uci/root/sbin/luci-reload b/libs/core/root/sbin/luci-reload index 24cf76064b..24cf76064b 100755 --- a/libs/uci/root/sbin/luci-reload +++ b/libs/core/root/sbin/luci-reload |