IFACE_PATTERNS_VIRTUAL = { }
-IFACE_PATTERNS_IGNORE = { "^wmaster%d", "^wifi%d", "^hwsim%d", "^imq%d", "^ifb%d", "^mon%.wlan%d", "^sit%d", "^gre%d", "^lo$" }
+IFACE_PATTERNS_IGNORE = { "^wmaster%d", "^wifi%d", "^hwsim%d", "^imq%d", "^ifb%d", "^mon%.wlan%d", "^sit%d", "^gre%d", "^gretap%d", "^ip6gre%d", "^ip6tnl%d", "^tunl%d", "^lo$" }
IFACE_PATTERNS_WIRELESS = { "^wlan%d", "^wl%d", "^ath%d", "^%w+%.network%d" }
local _protocols = { }
-local _interfaces, _bridge, _switch, _tunnel
+local _interfaces, _bridge, _switch, _tunnel, _swtopo
local _ubusnetcache, _ubusdevcache, _ubuswificache
local _uci
return true
end
end
- return _iface_virtual(x)
+ return false
end
-
function init(cursor)
_uci = cursor or _uci or uci.cursor()
_bridge = { }
_switch = { }
_tunnel = { }
+ _swtopo = { }
_ubusnetcache = { }
_ubusdevcache = { }
local n, i
for n, i in ipairs(nxo.getifaddrs()) do
local name = i.name:match("[^:]+")
- local prnt = name:match("^([^%.]+)%.")
if _iface_virtual(name) then
_tunnel[name] = true
end
- if _tunnel[name] or not _iface_ignore(name) then
+ if _tunnel[name] or not (_iface_ignore(name) or _iface_virtual(name)) then
_interfaces[name] = _interfaces[name] or {
idx = i.ifindex or n,
name = name,
ip6addrs = { }
}
- if prnt then
- _switch[name] = true
- _switch[prnt] = true
- end
-
if i.family == "packet" then
_interfaces[name].flags = i.flags
_interfaces[name].stats = i.data
end
end
+ -- read switch topology
+ local boardinfo = jsc.parse(nfs.readfile("/etc/board.json") or "")
+ if type(boardinfo) == "table" and type(boardinfo.switch) == "table" then
+ local switch, layout
+ for switch, layout in pairs(boardinfo.switch) do
+ if type(layout) == "table" and type(layout.ports) == "table" then
+ local _, port
+ local ports = { }
+ local nports = { }
+ local netdevs = { }
+
+ for _, port in ipairs(layout.ports) do
+ if type(port) == "table" and
+ type(port.num) == "number" and
+ (type(port.role) == "string" or
+ type(port.device) == "string")
+ then
+ local spec = {
+ num = port.num,
+ role = port.role or "cpu",
+ index = port.index or port.num
+ }
+
+ if port.device then
+ spec.device = port.device
+ spec.tagged = port.need_tag
+ netdevs[tostring(port.num)] = port.device
+ end
+
+ ports[#ports+1] = spec
+
+ if port.role then
+ nports[port.role] = (nports[port.role] or 0) + 1
+ end
+ end
+ end
+
+ table.sort(ports, function(a, b)
+ if a.role ~= b.role then
+ return (a.role < b.role)
+ end
+
+ return (a.index < b.index)
+ end)
+
+ local pnum, role
+ for _, port in ipairs(ports) do
+ if port.role ~= role then
+ role = port.role
+ pnum = 1
+ end
+
+ if role == "cpu" then
+ port.label = "CPU (%s)" % port.device
+ elseif nports[role] > 1 then
+ port.label = "%s %d" %{ role:upper(), pnum }
+ pnum = pnum + 1
+ else
+ port.label = role:upper()
+ end
+
+ port.role = nil
+ port.index = nil
+ end
+
+ _swtopo[switch] = {
+ ports = ports,
+ netdevs = netdevs
+ }
+ end
+ end
+ end
+
return _M
end
end
end
-local function swdev_from_board_json()
- local boardinfo = jsc.parse(nfs.readfile("/etc/board.json") or "")
- if type(boardinfo) == "table" and type(boardinfo.network) == "table" then
- local net, val
- for net, val in pairs(boardinfo.network) do
- if type(val) == "table" and type(val.ifname) == "string" and
- val.create_vlan == true
- then
- return val.ifname
- end
- end
- end
- return nil
-end
-
function get_interfaces(self)
local iface
local ifaces = { }
- local seen = { }
local nfs = { }
- local baseof = { }
-- find normal interfaces
_uci:foreach("network", "interface",
function(s)
for iface in utl.imatch(s.ifname) do
- if not _iface_ignore(iface) and not _wifi_iface(iface) then
- seen[iface] = true
+ if not _iface_ignore(iface) and not _iface_virtual(iface) and not _wifi_iface(iface) then
nfs[iface] = interface(iface)
end
end
end)
for iface in utl.kspairs(_interfaces) do
- if not (seen[iface] or _iface_ignore(iface) or _wifi_iface(iface)) then
+ if not (nfs[iface] or _iface_ignore(iface) or _iface_virtual(iface) or _wifi_iface(iface)) then
nfs[iface] = interface(iface)
end
end
-- find vlan interfaces
_uci:foreach("network", "switch_vlan",
function(s)
- if not s.device then
+ if type(s.ports) ~= "string" or
+ type(s.device) ~= "string" or
+ type(_swtopo[s.device]) ~= "table"
+ then
return
end
- local base = baseof[s.device]
- if not base then
- if not s.device:match("^eth%d") then
- local l
- for l in utl.execi("swconfig dev %q help 2>/dev/null" % s.device) do
- if not base then
- base = l:match("^%w+: (%w+)")
- end
+ local pnum, ptag
+ for pnum, ptag in s.ports:gmatch("(%d+)([tu]?)") do
+ local netdev = _swtopo[s.device].netdevs[pnum]
+ if netdev then
+ if not nfs[netdev] then
+ nfs[netdev] = interface(netdev)
end
- if not base or not base:match("^eth%d") then
- base = swdev_from_board_json() or "eth0"
+ _switch[netdev] = true
+
+ if ptag == "t" then
+ local vid = tonumber(s.vid or s.vlan)
+ if vid ~= nil and vid >= 0 and vid <= 4095 then
+ local iface = "%s.%d" %{ netdev, vid }
+ if not nfs[iface] then
+ nfs[iface] = interface(iface)
+ end
+ _switch[iface] = true
+ end
end
- else
- base = s.device
- end
- baseof[s.device] = base
- 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)
end
function get_wannet(self)
- local net = self:get_status_by_route("0.0.0.0", 0)
- return net and network(net)
+ local net, stat = self:get_status_by_route("0.0.0.0", 0)
+ return net and network(net, stat.proto)
end
function get_wandev(self)
end
function get_wan6net(self)
- local net = self:get_status_by_route("::", 0)
- return net and network(net)
+ local net, stat = self:get_status_by_route("::", 0)
+ return net and network(net, stat.proto)
end
function get_wan6dev(self)
return stat and interface(stat.l3_device or stat.device)
end
+function get_switch_topologies(self)
+ return _swtopo
+end
+
function network(name, proto)
if name then
function interface.shortname(self)
if self.wif then
- return "%s %q" %{
- self.wif:active_mode(),
- self.wif:active_ssid() or self.wif:active_bssid()
- }
+ return self.wif:shortname()
else
return self.ifname
end
return "%s: %s %q" %{
lng.translate("Wireless Network"),
self.wif:active_mode(),
- self.wif:active_ssid() or self.wif:active_bssid()
+ self.wif:active_ssid() or self.wif:active_bssid() or self.wif:id()
}
else
return "%s: %q" %{ self:get_type_i18n(), self:name() }
elseif x == "switch" then
return lng.translate("Ethernet Switch")
elseif x == "vlan" then
- return lng.translate("VLAN Interface")
+ if _switch[self.ifname] then
+ return lng.translate("Switch VLAN")
+ else
+ return lng.translate("Software VLAN")
+ end
elseif x == "tunnel" then
return lng.translate("Tunnel Interface")
else
function wifinet.shortname(self)
return "%s %q" %{
lng.translate(self:active_mode()),
- self:active_ssid() or self:active_bssid()
+ self:active_ssid() or self:active_bssid() or self:id()
}
end
return "%s: %s %q (%s)" %{
lng.translate("Wireless Network"),
lng.translate(self:active_mode()),
- self:active_ssid() or self:active_bssid(),
+ self:active_ssid() or self:active_bssid() or self:id(),
self:ifname()
}
end