luci-base: Show multiple upstream interface 2140/head
authorKristian Evensen <kristian.evensen@gmail.com>
Sun, 9 Sep 2018 15:27:28 +0000 (17:27 +0200)
committerKristian Evensen <kristian.evensen@gmail.com>
Wed, 19 Sep 2018 09:01:38 +0000 (11:01 +0200)
Several devices have multiple upstream interfaces, for example a fixed
and a mobile broadband connection. Currently, only one upstream
interface is shown per address family in Luci. So in my example, one of
the interfaces would not appear on the Status-page.

This PR introduces support for showing multiple upstream interfaces on
the Status-page. The code is not very complicated. get_status_by_route()
has been extended to return a list of all routes, and
get_wannet()/get_wan6net() now returns all upstream interfaces.

I could not find any other (active) users of these three functions than
calls triggered from the Status-page, so changing the default behavior
should be fine. get_wandev()/get_wan6dev() called get_status_by_route(),
but I could not find any place where those functions were called. I
removed the dev-functions instead of keeping the old
get_status_by_route().

On the status page, the wan/wan6-variables have been replaced with
arrays. When populating the html, we now iterate through these arrays
and create one element for each interface.

I have tested the code with different interface types, v4, v6, as well as
disconnecting and connecting interfaces. The status is updated and the
correct interfaces (or sometimes none at all) are shown.

Signed-off-by: Kristian Evensen <kristian.evensen@gmail.com>
modules/luci-base/luasrc/model/network.lua
modules/luci-mod-admin-full/luasrc/view/admin_status/index.htm

index cce559aab1740166f9efa82989f01b87f9f5c3db..7f7397032f95db38c8977ed508485867f0c7d680 100644 (file)
@@ -813,6 +813,7 @@ function del_wifinet(self, net)
 end
 
 function get_status_by_route(self, addr, mask)
+       local route_statuses = { }
        local _, object
        for _, object in ipairs(utl.ubus()) do
                local net = object:match("^network%.interface%.(.+)")
@@ -822,12 +823,14 @@ function get_status_by_route(self, addr, mask)
                                local rt
                                for _, rt in ipairs(s.route) do
                                        if not rt.table and rt.target == addr and rt.mask == mask then
-                                               return net, s
+                                               route_statuses[net] = s
                                        end
                                end
                        end
                end
        end
+
+       return route_statuses
 end
 
 function get_status_by_address(self, addr)
@@ -856,24 +859,28 @@ function get_status_by_address(self, addr)
        end
 end
 
-function get_wannet(self)
-       local net, stat = self:get_status_by_route("0.0.0.0", 0)
-       return net and network(net, stat.proto)
-end
+function get_wan_networks(self)
+       local k, v
+       local wan_nets = { }
+       local route_statuses = self:get_status_by_route("0.0.0.0", 0)
 
-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
+       for k, v in pairs(route_statuses) do
+               wan_nets[#wan_nets+1] = network(k, v.proto)
+       end
 
-function get_wan6net(self)
-       local net, stat = self:get_status_by_route("::", 0)
-       return net and network(net, stat.proto)
+       return wan_nets
 end
 
-function get_wan6dev(self)
-       local _, stat = self:get_status_by_route("::", 0)
-       return stat and interface(stat.l3_device or stat.device)
+function get_wan6_networks(self)
+       local k, v
+       local wan6_nets = { }
+       local route_statuses = self:get_status_by_route("::", 0)
+
+       for k, v in pairs(route_statuses) do
+               wan6_nets[#wan6_nets+1] = network(k, v.proto)
+       end
+
+       return wan6_nets
 end
 
 function get_switch_topologies(self)
index 29a03f2554527aa408a63d10f989a493e5d01185..8820ae1cf350b8db0798f3caf09914915b612d4e 100644 (file)
@@ -35,8 +35,8 @@
 
        if luci.http.formvalue("status") == "1" then
                local ntm = require "luci.model.network".init()
-               local wan = ntm:get_wannet()
-               local wan6 = ntm:get_wan6net()
+               local wan_nets = ntm:get_wan_networks()
+               local wan6_nets = ntm:get_wan6_networks()
 
                local conn_count = tonumber(
                        fs.readfile("/proc/sys/net/netfilter/nf_conntrack_count") or "") or 0
                        wifinets   = stat.wifi_networks()
                }
 
-               if wan then
-                       local dev = wan:get_interface()
-                       local link = dev and ipc.link(dev:name())
-                       rv.wan = {
-                               ipaddr  = wan:ipaddr(),
-                               gwaddr  = wan:gwaddr(),
-                               netmask = wan:netmask(),
-                               dns     = wan:dnsaddrs(),
-                               expires = wan:expires(),
-                               uptime  = wan:uptime(),
-                               proto   = wan:proto(),
-                               i18n    = wan:get_i18n(),
-                               ifname  = wan:ifname(),
-                               link    = wan:adminlink(),
-                               mac     = dev and dev:mac(),
-                               type    = dev and dev:type(),
-                               name    = dev and dev:get_i18n(),
-                               ether   = link and link.type == 1
-                       }
+               if #wan_nets > 0 then
+                       local k, v
+
+                       rv.wan = { }
+
+                       for k, v in pairs(wan_nets) do
+                               local dev = v:get_interface()
+                               local link = dev and ipc.link(dev:name())
+
+                               local wan_info = {
+                                       ipaddr  = v:ipaddr(),
+                                       gwaddr  = v:gwaddr(),
+                                       netmask = v:netmask(),
+                                       dns     = v:dnsaddrs(),
+                                       expires = v:expires(),
+                                       uptime  = v:uptime(),
+                                       proto   = v:proto(),
+                                       i18n    = v:get_i18n(),
+                                       ifname  = v:ifname(),
+                                       link    = v:adminlink(),
+                                       mac     = dev and dev:mac(),
+                                       type    = dev and dev:type(),
+                                       name    = dev and dev:get_i18n(),
+                                       ether   = link and link.type == 1
+                               }
+
+                               rv.wan[#rv.wan+1] = wan_info
+                       end
                end
 
-               if wan6 then
-                       local dev = wan6:get_interface()
-                       local link = dev and ipc.link(dev:name())
-                       rv.wan6 = {
-                               ip6addr   = wan6:ip6addr(),
-                               gw6addr   = wan6:gw6addr(),
-                               dns       = wan6:dns6addrs(),
-                               ip6prefix = wan6:ip6prefix(),
-                               uptime    = wan6:uptime(),
-                               proto     = wan6:proto(),
-                               i18n      = wan6:get_i18n(),
-                               ifname    = wan6:ifname(),
-                               link      = wan6:adminlink(),
-                               mac       = dev and dev:mac(),
-                               type      = dev and dev:type(),
-                               name      = dev and dev:get_i18n(),
-                               ether     = link and link.type == 1
-                       }
+               if #wan6_nets > 0 then
+                       local k, v
+
+                       rv.wan6 = { }
+
+                       for k, v in pairs(wan6_nets) do
+                               local dev = v:get_interface()
+                               local link = dev and ipc.link(dev:name())
+                               local wan6_info = {
+                                       ip6addr   = v:ip6addr(),
+                                       gw6addr   = v:gw6addr(),
+                                       dns       = v:dns6addrs(),
+                                       ip6prefix = v:ip6prefix(),
+                                       uptime    = v:uptime(),
+                                       proto     = v:proto(),
+                                       i18n      = v:get_i18n(),
+                                       ifname    = v:ifname(),
+                                       link      = v:adminlink(),
+                                       mac       = dev and dev:mac(),
+                                       type      = dev and dev:type(),
+                                       name      = dev and dev:get_i18n(),
+                                       ether     = link and link.type == 1
+                               }
+
+                               rv.wan6[#rv.wan6+1] = wan6_info
+                       end
                end
 
                if has_dsl then
                        while (us.lastElementChild)
                                us.removeChild(us.lastElementChild);
 
-                       var ifc = info.wan || {};
+                       var wan_list = info.wan || [];
+
+                       for (var i = 0; i < wan_list.length; i++) {
+                               var ifc = wan_list[i];
 
-                       us.appendChild(renderBox(
-                               '<%:IPv4 Upstream%>',
-                               (ifc.ifname && ifc.proto != 'none'),
-                               [ E('div', {}, renderBadge(
-                                       '<%=resource%>/icons/%s.png'.format((ifc && ifc.type) ? ifc.type : 'ethernet_disabled'), null,
+                               us.appendChild(renderBox(
+                                       '<%:IPv4 Upstream%>',
+                                       (ifc.ifname && ifc.proto != 'none'),
+                                       [ E('div', {}, renderBadge(
+                                       '<%=resource%>' + '/icons/%s.png'.format((ifc && ifc.type) ? ifc.type : 'ethernet_disabled'), null,
                                        '<%:Device%>', ifc ? (ifc.name || ifc.ifname || '-') : '-',
                                        '<%:MAC-Address%>', (ifc && ifc.ether) ? ifc.mac : null)) ],
-                               '<%:Protocol%>', ifc.i18n || E('em', '<%:Not connected%>'),
-                               '<%:Address%>', (ifc.ipaddr) ? ifc.ipaddr : '0.0.0.0',
-                               '<%:Netmask%>', (ifc.netmask && ifc.netmask != ifc.ipaddr) ? ifc.netmask : '255.255.255.255',
-                               '<%:Gateway%>', (ifc.gwaddr) ? ifc.gwaddr : '0.0.0.0',
-                               '<%:DNS%> 1', (ifc.dns) ? ifc.dns[0] : null,
-                               '<%:DNS%> 2', (ifc.dns) ? ifc.dns[1] : null,
-                               '<%:DNS%> 3', (ifc.dns) ? ifc.dns[2] : null,
-                               '<%:DNS%> 4', (ifc.dns) ? ifc.dns[3] : null,
-                               '<%:DNS%> 5', (ifc.dns) ? ifc.dns[4] : null,
-                               '<%:Expires%>', (ifc.expires > -1) ? '%t'.format(ifc.expires) : null,
-                               '<%:Connected%>', (ifc.uptime > 0) ? '%t'.format(ifc.uptime) : null));
+                                       '<%:Protocol%>', ifc.i18n || E('em', '<%:Not connected%>'),
+                                       '<%:Address%>', (ifc.ipaddr) ? ifc.ipaddr : '0.0.0.0',
+                                       '<%:Netmask%>', (ifc.netmask && ifc.netmask != ifc.ipaddr) ? ifc.netmask : '255.255.255.255',
+                                       '<%:Gateway%>', (ifc.gwaddr) ? ifc.gwaddr : '0.0.0.0',
+                                       '<%:DNS%> 1', (ifc.dns) ? ifc.dns[0] : null,
+                                       '<%:DNS%> 2', (ifc.dns) ? ifc.dns[1] : null,
+                                       '<%:DNS%> 3', (ifc.dns) ? ifc.dns[2] : null,
+                                       '<%:DNS%> 4', (ifc.dns) ? ifc.dns[3] : null,
+                                       '<%:DNS%> 5', (ifc.dns) ? ifc.dns[4] : null,
+                                       '<%:Expires%>', (ifc.expires > -1) ? '%t'.format(ifc.expires) : null,
+                                       '<%:Connected%>', (ifc.uptime > 0) ? '%t'.format(ifc.uptime) : null));
+                       }
 
                        <% if has_ipv6 then %>
-                       var ifc6 = info.wan6 || {};
-
-                       us.appendChild(renderBox(
-                               '<%:IPv6 Upstream%>',
-                               (ifc6.ifname && ifc6.proto != 'none'),
-                               [ E('div', {}, renderBadge(
-                                       '<%=resource%>/icons/%s.png'.format(ifc6.type || 'ethernet_disabled'), null,
-                                       '<%:Device%>', ifc6 ? (ifc6.name || ifc6.ifname || '-') : '-',
-                                       '<%:MAC-Address%>', (ifc6 && ifc6.ether) ? ifc6.mac : null)) ],
-                               '<%:Protocol%>', ifc6.i18n ? (ifc6.i18n + (ifc6.proto === 'dhcp' && ifc6.ip6prefix ? '-PD' : '')) : E('em', '<%:Not connected%>'),
-                               '<%:Prefix Delegated%>', ifc6.ip6prefix,
-                               '<%:Address%>', (ifc6.ip6prefix) ? (ifc6.ip6addr || null) : (ifc6.ipaddr || '::'),
-                               '<%:Gateway%>', (ifc6.gw6addr) ? ifc6.gw6addr : '::',
-                               '<%:DNS%> 1', (ifc6.dns) ? ifc6.dns[0] : null,
-                               '<%:DNS%> 2', (ifc6.dns) ? ifc6.dns[1] : null,
-                               '<%:DNS%> 3', (ifc6.dns) ? ifc6.dns[2] : null,
-                               '<%:DNS%> 4', (ifc6.dns) ? ifc6.dns[3] : null,
-                               '<%:DNS%> 5', (ifc6.dns) ? ifc6.dns[4] : null,
-                               '<%:Connected%>', (ifc6.uptime > 0) ? '%t'.format(ifc6.uptime) : null));
+                       var wan6_list = info.wan6 || [];
+
+                       for (var i = 0; i < wan6_list.length; i++) {
+                               var ifc6 = wan6_list[i];
+
+                               us.appendChild(renderBox(
+                                       '<%:IPv6 Upstream%>',
+                                       (ifc6.ifname && ifc6.proto != 'none'),
+                                       [ E('div', {}, renderBadge(
+                                               '<%=resource%>/icons/%s.png'.format(ifc6.type || 'ethernet_disabled'), null,
+                                               '<%:Device%>', ifc6 ? (ifc6.name || ifc6.ifname || '-') : '-',
+                                               '<%:MAC-Address%>', (ifc6 && ifc6.ether) ? ifc6.mac : null)) ],
+                                       '<%:Protocol%>', ifc6.i18n ? (ifc6.i18n + (ifc6.proto === 'dhcp' && ifc6.ip6prefix ? '-PD' : '')) : E('em', '<%:Not connected%>'),
+                                       '<%:Prefix Delegated%>', ifc6.ip6prefix,
+                                       '<%:Address%>', (ifc6.ip6prefix) ? (ifc6.ip6addr || null) : (ifc6.ipaddr || '::'),
+                                       '<%:Gateway%>', (ifc6.gw6addr) ? ifc6.gw6addr : '::',
+                                       '<%:DNS%> 1', (ifc6.dns) ? ifc6.dns[0] : null,
+                                       '<%:DNS%> 2', (ifc6.dns) ? ifc6.dns[1] : null,
+                                       '<%:DNS%> 3', (ifc6.dns) ? ifc6.dns[2] : null,
+                                       '<%:DNS%> 4', (ifc6.dns) ? ifc6.dns[3] : null,
+                                       '<%:DNS%> 5', (ifc6.dns) ? ifc6.dns[4] : null,
+                                       '<%:Connected%>', (ifc6.uptime > 0) ? '%t'.format(ifc6.uptime) : null));
+                       }
                        <% end %>
 
                        <% if has_dsl then %>