Skip to content

Commit

Permalink
bridge: netlink: make setlink/dellink notifications more accurate
Browse files Browse the repository at this point in the history
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 <[email protected]>
Acked-by: Stephen Hemminger <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
Nikolay Aleksandrov authored and davem330 committed Oct 29, 2017
1 parent 5b52a4c commit e19b42a
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 24 deletions.
44 changes: 26 additions & 18 deletions net/bridge/br_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,7 @@ int br_getlink(struct sk_buff *skb, u32 pid, u32 seq,
}

static int br_vlan_info(struct net_bridge *br, struct net_bridge_port *p,
int cmd, struct bridge_vlan_info *vinfo)
int cmd, struct bridge_vlan_info *vinfo, bool *changed)
{
int err = 0;

Expand All @@ -517,21 +517,24 @@ static int br_vlan_info(struct net_bridge *br, struct net_bridge_port *p,
* per-VLAN entry as well
*/
err = nbp_vlan_add(p, vinfo->vid, vinfo->flags);
if (err)
break;
} else {
vinfo->flags |= BRIDGE_VLAN_INFO_BRENTRY;
err = br_vlan_add(br, vinfo->vid, vinfo->flags);
}
if (!err)
*changed = true;
break;

case RTM_DELLINK:
if (p) {
nbp_vlan_delete(p, vinfo->vid);
if (vinfo->flags & BRIDGE_VLAN_INFO_MASTER)
br_vlan_delete(p->br, vinfo->vid);
} else {
br_vlan_delete(br, vinfo->vid);
if (!nbp_vlan_delete(p, vinfo->vid))
*changed = true;

if ((vinfo->flags & BRIDGE_VLAN_INFO_MASTER) &&
!br_vlan_delete(p->br, vinfo->vid))
*changed = true;
} else if (!br_vlan_delete(br, vinfo->vid)) {
*changed = true;
}
break;
}
Expand All @@ -542,7 +545,8 @@ static int br_vlan_info(struct net_bridge *br, struct net_bridge_port *p,
static int br_process_vlan_info(struct net_bridge *br,
struct net_bridge_port *p, int cmd,
struct bridge_vlan_info *vinfo_curr,
struct bridge_vlan_info **vinfo_last)
struct bridge_vlan_info **vinfo_last,
bool *changed)
{
if (!vinfo_curr->vid || vinfo_curr->vid >= VLAN_VID_MASK)
return -EINVAL;
Expand Down Expand Up @@ -572,7 +576,7 @@ static int br_process_vlan_info(struct net_bridge *br,
sizeof(struct bridge_vlan_info));
for (v = (*vinfo_last)->vid; v <= vinfo_curr->vid; v++) {
tmp_vinfo.vid = v;
err = br_vlan_info(br, p, cmd, &tmp_vinfo);
err = br_vlan_info(br, p, cmd, &tmp_vinfo, changed);
if (err)
break;
}
Expand All @@ -581,13 +585,13 @@ static int br_process_vlan_info(struct net_bridge *br,
return err;
}

return br_vlan_info(br, p, cmd, vinfo_curr);
return br_vlan_info(br, p, cmd, vinfo_curr, changed);
}

static int br_afspec(struct net_bridge *br,
struct net_bridge_port *p,
struct nlattr *af_spec,
int cmd)
int cmd, bool *changed)
{
struct bridge_vlan_info *vinfo_curr = NULL;
struct bridge_vlan_info *vinfo_last = NULL;
Expand All @@ -607,7 +611,8 @@ static int br_afspec(struct net_bridge *br,
return err;
err = br_process_vlan_tunnel_info(br, p, cmd,
&tinfo_curr,
&tinfo_last);
&tinfo_last,
changed);
if (err)
return err;
break;
Expand All @@ -616,7 +621,7 @@ static int br_afspec(struct net_bridge *br,
return -EINVAL;
vinfo_curr = nla_data(attr);
err = br_process_vlan_info(br, p, cmd, vinfo_curr,
&vinfo_last);
&vinfo_last, changed);
if (err)
return err;
break;
Expand Down Expand Up @@ -804,6 +809,7 @@ int br_setlink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags)
struct nlattr *afspec;
struct net_bridge_port *p;
struct nlattr *tb[IFLA_BRPORT_MAX + 1];
bool changed = false;
int err = 0;

protinfo = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_PROTINFO);
Expand Down Expand Up @@ -839,14 +845,15 @@ int br_setlink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags)
}
if (err)
goto out;
changed = true;
}

if (afspec) {
err = br_afspec((struct net_bridge *)netdev_priv(dev), p,
afspec, RTM_SETLINK);
afspec, RTM_SETLINK, &changed);
}

if (err == 0)
if (changed)
br_ifinfo_notify(RTM_NEWLINK, p);
out:
return err;
Expand All @@ -857,6 +864,7 @@ int br_dellink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags)
{
struct nlattr *afspec;
struct net_bridge_port *p;
bool changed = false;
int err = 0;

afspec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
Expand All @@ -869,8 +877,8 @@ int br_dellink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags)
return -EINVAL;

err = br_afspec((struct net_bridge *)netdev_priv(dev), p,
afspec, RTM_DELLINK);
if (err == 0)
afspec, RTM_DELLINK, &changed);
if (changed)
/* Send RTM_NEWLINK because userspace
* expects RTM_NEWLINK for vlan dels
*/
Expand Down
14 changes: 9 additions & 5 deletions net/bridge/br_netlink_tunnel.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
}

Expand Down Expand Up @@ -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;

Expand All @@ -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++;
Expand All @@ -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));
Expand Down
3 changes: 2 additions & 1 deletion net/bridge/br_private_tunnel.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ 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 br_get_vlan_tunnel_info_size(struct net_bridge_vlan_group *vg);
int br_fill_vlan_tunnel_info(struct sk_buff *skb,
struct net_bridge_vlan_group *vg);
Expand Down

0 comments on commit e19b42a

Please sign in to comment.