bridge: netlink: make setlink/dellink notifications more accurate

Before this patch we had cases that either sent notifications when there
were in fact no changes (e.g. non-existent vlan delete) or didn't send
notifications when there were changes (e.g. vlan add range with an error in
the middle, port flags change + vlan update error). This patch sends down
a boolean to the functions setlink/dellink use and if there is even a
single configuration change (port flag, vlan add/del, port state) then
we always send a notification. This is all done to keep backwards
compatibility with the opportunistic vlan delete, where one could
specify a vlan range that has missing vlans inside and still everything
in that range will be cleared, this is mostly used to clear the whole
vlan config with a single call, i.e. range 1-4094.

Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
Acked-by: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/net/bridge/br_netlink_tunnel.c b/net/bridge/br_netlink_tunnel.c
index 3712c7f..da8cb99 100644
--- a/net/bridge/br_netlink_tunnel.c
+++ b/net/bridge/br_netlink_tunnel.c
@@ -198,7 +198,7 @@ static const struct nla_policy vlan_tunnel_policy[IFLA_BRIDGE_VLAN_TUNNEL_MAX +
 };
 
 static int br_vlan_tunnel_info(struct net_bridge_port *p, int cmd,
-			       u16 vid, u32 tun_id)
+			       u16 vid, u32 tun_id, bool *changed)
 {
 	int err = 0;
 
@@ -208,9 +208,12 @@ static int br_vlan_tunnel_info(struct net_bridge_port *p, int cmd,
 	switch (cmd) {
 	case RTM_SETLINK:
 		err = nbp_vlan_tunnel_info_add(p, vid, tun_id);
+		if (!err)
+			*changed = true;
 		break;
 	case RTM_DELLINK:
-		nbp_vlan_tunnel_info_delete(p, vid);
+		if (!nbp_vlan_tunnel_info_delete(p, vid))
+			*changed = true;
 		break;
 	}
 
@@ -254,7 +257,8 @@ int br_parse_vlan_tunnel_info(struct nlattr *attr,
 int br_process_vlan_tunnel_info(struct net_bridge *br,
 				struct net_bridge_port *p, int cmd,
 				struct vtunnel_info *tinfo_curr,
-				struct vtunnel_info *tinfo_last)
+				struct vtunnel_info *tinfo_last,
+				bool *changed)
 {
 	int err;
 
@@ -272,7 +276,7 @@ int br_process_vlan_tunnel_info(struct net_bridge *br,
 			return -EINVAL;
 		t = tinfo_last->tunid;
 		for (v = tinfo_last->vid; v <= tinfo_curr->vid; v++) {
-			err = br_vlan_tunnel_info(p, cmd, v, t);
+			err = br_vlan_tunnel_info(p, cmd, v, t, changed);
 			if (err)
 				return err;
 			t++;
@@ -283,7 +287,7 @@ int br_process_vlan_tunnel_info(struct net_bridge *br,
 		if (tinfo_last->flags)
 			return -EINVAL;
 		err = br_vlan_tunnel_info(p, cmd, tinfo_curr->vid,
-					  tinfo_curr->tunid);
+					  tinfo_curr->tunid, changed);
 		if (err)
 			return err;
 		memset(tinfo_last, 0, sizeof(struct vtunnel_info));