luci-mod-admin-full: auto-migrate ifnames when changing VLAN configuration
authorJo-Philipp Wich <jo@mein.io>
Mon, 29 May 2017 06:45:38 +0000 (08:45 +0200)
committerJo-Philipp Wich <jo@mein.io>
Wed, 31 May 2017 22:25:38 +0000 (00:25 +0200)
This change extends the switch VLAN configuration page to automatically
adjust interface ifname options when altering VLAN settings.

For example "eth0" is changed to "eth0.1" when a previously untagged LAN
VLAN is switched to tagged on the CPU port and vice versa.

Notifications are displayed in the page header if an auto migration was
performed.

This change should make the switch configuration more user friendly and
less prone to soft bricking.

Signed-off-by: Jo-Philipp Wich <jo@mein.io>
modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/vlan.lua

index 902767c903826d8aa3303012c0b1a4b3dcd0a9e1..89a73a5ca88909c3e1274005602dbc0feb1f0d24 100644 (file)
@@ -12,6 +12,35 @@ nw.init(m.uci)
 
 local topologies = nw:get_switch_topologies() or {}
 
+local update_interfaces = function(old_ifname, new_ifname)
+       local info = { }
+
+       m.uci:foreach("network", "interface", function(section)
+               local old_ifnames = m.uci:get("network", section[".name"], "ifname")
+               local new_ifnames = { }
+               local cur_ifname
+               local changed = false
+               for cur_ifname in luci.util.imatch(old_ifnames) do
+                       if cur_ifname == old_ifname then
+                               new_ifnames[#new_ifnames+1] = new_ifname
+                               changed = true
+                       else
+                               new_ifnames[#new_ifnames+1] = cur_ifname
+                       end
+               end
+               if changed then
+                       m.uci:set("network", section[".name"], "ifname", table.concat(new_ifnames, " "))
+
+                       info[#info+1] = translatef("Interface %q device auto-migrated from %q to %q.",
+                               section[".name"], old_ifname, new_ifname)
+               end
+       end)
+
+       if #info > 0 then
+               m.message = (m.message and m.message .. "\n" or "") .. table.concat(info, "\n")
+       end
+end
+
 m.uci:foreach("network", "switch",
        function(x)
                local sid         = x['.name']
@@ -259,17 +288,32 @@ m.uci:foreach("network", "switch",
 
                -- When writing the "vid" or "vlan" option, serialize the port states
                -- as well and write them as "ports" option to uci.
-               vid.write = function(self, section, value)
+               vid.write = function(self, section, new_vid)
                        local o
                        local p = { }
-
                        for _, o in ipairs(port_opts) do
-                               local v = o:formvalue(section)
-                               if v == "t" then
-                                       p[#p+1] = o.option .. v
-                               elseif v == "u" then
+                               local new_tag = o:formvalue(section)
+                               if new_tag == "t" then
+                                       p[#p+1] = o.option .. new_tag
+                               elseif new_tag == "u" then
                                        p[#p+1] = o.option
                                end
+
+                               if o.info and o.info.device then
+                                       local old_tag = o:cfgvalue(section)
+                                       local old_vid = self:cfgvalue(section)
+                                       if old_tag ~= new_tag or old_vid ~= new_vid then
+                                               local old_ifname = (old_tag == "u") and o.info.device
+                                                       or "%s.%s" %{ o.info.device, old_vid }
+
+                                               local new_ifname = (new_tag == "u") and o.info.device
+                                                       or "%s.%s" %{ o.info.device, new_vid }
+
+                                               if old_ifname ~= new_ifname then
+                                                       update_interfaces(old_ifname, new_ifname)
+                                               end
+                                       end
+                               end
                        end
 
                        if enable_vlan4k then
@@ -277,7 +321,7 @@ m.uci:foreach("network", "switch",
                        end
 
                        m:set(section, "ports", table.concat(p, " "))
-                       return Value.write(self, section, value)
+                       return Value.write(self, section, new_vid)
                end
 
                -- Fallback to "vlan" option if "vid" option is supported but unset.
@@ -301,6 +345,7 @@ m.uci:foreach("network", "switch",
                        po.cfgvalue = portvalue
                        po.validate = portvalidate
                        po.write    = function() end
+                       po.info     = pt
 
                        port_opts[#port_opts+1] = po
                end