Commit 304ae3bf authored by Vladimir Oltean's avatar Vladimir Oltean Committed by David S. Miller

net: bridge: offload all port flags at once in br_setport

If for example this command:

ip link set swp0 type bridge_slave flood off mcast_flood off learning off

succeeded at configuring BR_FLOOD and BR_MCAST_FLOOD but not at
BR_LEARNING, there would be no attempt to revert the partial state in
any way. Arguably, if the user changes more than one flag through the
same netlink command, this one _should_ be all or nothing, which means
it should be passed through switchdev as all or nothing.
Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Acked-by: default avatarNikolay Aleksandrov <nikolay@nvidia.com>
Reviewed-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4c08c586
...@@ -853,87 +853,58 @@ static int br_set_port_state(struct net_bridge_port *p, u8 state) ...@@ -853,87 +853,58 @@ static int br_set_port_state(struct net_bridge_port *p, u8 state)
} }
/* Set/clear or port flags based on attribute */ /* Set/clear or port flags based on attribute */
static int br_set_port_flag(struct net_bridge_port *p, struct nlattr *tb[], static void br_set_port_flag(struct net_bridge_port *p, struct nlattr *tb[],
int attrtype, unsigned long mask) int attrtype, unsigned long mask)
{ {
unsigned long flags;
int err;
if (!tb[attrtype]) if (!tb[attrtype])
return 0; return;
if (nla_get_u8(tb[attrtype])) if (nla_get_u8(tb[attrtype]))
flags = p->flags | mask; p->flags |= mask;
else else
flags = p->flags & ~mask; p->flags &= ~mask;
err = br_switchdev_set_port_flag(p, flags, mask);
if (err)
return err;
p->flags = flags;
return 0;
} }
/* Process bridge protocol info on port */ /* Process bridge protocol info on port */
static int br_setport(struct net_bridge_port *p, struct nlattr *tb[]) static int br_setport(struct net_bridge_port *p, struct nlattr *tb[])
{ {
unsigned long old_flags = p->flags; unsigned long old_flags, changed_mask;
bool br_vlan_tunnel_old = false; bool br_vlan_tunnel_old;
int err; int err;
err = br_set_port_flag(p, tb, IFLA_BRPORT_MODE, BR_HAIRPIN_MODE); old_flags = p->flags;
if (err) br_vlan_tunnel_old = (old_flags & BR_VLAN_TUNNEL) ? true : false;
return err;
br_set_port_flag(p, tb, IFLA_BRPORT_MODE, BR_HAIRPIN_MODE);
err = br_set_port_flag(p, tb, IFLA_BRPORT_GUARD, BR_BPDU_GUARD); br_set_port_flag(p, tb, IFLA_BRPORT_GUARD, BR_BPDU_GUARD);
if (err) br_set_port_flag(p, tb, IFLA_BRPORT_FAST_LEAVE,
return err; BR_MULTICAST_FAST_LEAVE);
br_set_port_flag(p, tb, IFLA_BRPORT_PROTECT, BR_ROOT_BLOCK);
err = br_set_port_flag(p, tb, IFLA_BRPORT_FAST_LEAVE, BR_MULTICAST_FAST_LEAVE); br_set_port_flag(p, tb, IFLA_BRPORT_LEARNING, BR_LEARNING);
if (err) br_set_port_flag(p, tb, IFLA_BRPORT_UNICAST_FLOOD, BR_FLOOD);
return err; br_set_port_flag(p, tb, IFLA_BRPORT_MCAST_FLOOD, BR_MCAST_FLOOD);
br_set_port_flag(p, tb, IFLA_BRPORT_MCAST_TO_UCAST,
err = br_set_port_flag(p, tb, IFLA_BRPORT_PROTECT, BR_ROOT_BLOCK); BR_MULTICAST_TO_UNICAST);
if (err) br_set_port_flag(p, tb, IFLA_BRPORT_BCAST_FLOOD, BR_BCAST_FLOOD);
return err; br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP, BR_PROXYARP);
br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP_WIFI, BR_PROXYARP_WIFI);
err = br_set_port_flag(p, tb, IFLA_BRPORT_LEARNING, BR_LEARNING); br_set_port_flag(p, tb, IFLA_BRPORT_VLAN_TUNNEL, BR_VLAN_TUNNEL);
if (err) br_set_port_flag(p, tb, IFLA_BRPORT_NEIGH_SUPPRESS, BR_NEIGH_SUPPRESS);
return err; br_set_port_flag(p, tb, IFLA_BRPORT_ISOLATED, BR_ISOLATED);
err = br_set_port_flag(p, tb, IFLA_BRPORT_UNICAST_FLOOD, BR_FLOOD); changed_mask = old_flags ^ p->flags;
if (err)
return err; err = br_switchdev_set_port_flag(p, p->flags, changed_mask);
if (err) {
err = br_set_port_flag(p, tb, IFLA_BRPORT_MCAST_FLOOD, BR_MCAST_FLOOD); p->flags = old_flags;
if (err)
return err;
err = br_set_port_flag(p, tb, IFLA_BRPORT_MCAST_TO_UCAST, BR_MULTICAST_TO_UNICAST);
if (err)
return err;
err = br_set_port_flag(p, tb, IFLA_BRPORT_BCAST_FLOOD, BR_BCAST_FLOOD);
if (err)
return err;
err = br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP, BR_PROXYARP);
if (err)
return err;
err = br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP_WIFI, BR_PROXYARP_WIFI);
if (err)
return err;
br_vlan_tunnel_old = (p->flags & BR_VLAN_TUNNEL) ? true : false;
err = br_set_port_flag(p, tb, IFLA_BRPORT_VLAN_TUNNEL, BR_VLAN_TUNNEL);
if (err)
return err; return err;
}
if (br_vlan_tunnel_old && !(p->flags & BR_VLAN_TUNNEL)) if (br_vlan_tunnel_old && !(p->flags & BR_VLAN_TUNNEL))
nbp_vlan_tunnel_info_flush(p); nbp_vlan_tunnel_info_flush(p);
br_port_flags_change(p, changed_mask);
if (tb[IFLA_BRPORT_COST]) { if (tb[IFLA_BRPORT_COST]) {
err = br_stp_set_path_cost(p, nla_get_u32(tb[IFLA_BRPORT_COST])); err = br_stp_set_path_cost(p, nla_get_u32(tb[IFLA_BRPORT_COST]));
if (err) if (err)
...@@ -982,15 +953,6 @@ static int br_setport(struct net_bridge_port *p, struct nlattr *tb[]) ...@@ -982,15 +953,6 @@ static int br_setport(struct net_bridge_port *p, struct nlattr *tb[])
p->group_fwd_mask = fwd_mask; p->group_fwd_mask = fwd_mask;
} }
err = br_set_port_flag(p, tb, IFLA_BRPORT_NEIGH_SUPPRESS,
BR_NEIGH_SUPPRESS);
if (err)
return err;
err = br_set_port_flag(p, tb, IFLA_BRPORT_ISOLATED, BR_ISOLATED);
if (err)
return err;
if (tb[IFLA_BRPORT_BACKUP_PORT]) { if (tb[IFLA_BRPORT_BACKUP_PORT]) {
struct net_device *backup_dev = NULL; struct net_device *backup_dev = NULL;
u32 backup_ifindex; u32 backup_ifindex;
...@@ -1008,7 +970,6 @@ static int br_setport(struct net_bridge_port *p, struct nlattr *tb[]) ...@@ -1008,7 +970,6 @@ static int br_setport(struct net_bridge_port *p, struct nlattr *tb[])
return err; return err;
} }
br_port_flags_change(p, old_flags ^ p->flags);
return 0; return 0;
} }
......
...@@ -65,16 +65,18 @@ int br_switchdev_set_port_flag(struct net_bridge_port *p, ...@@ -65,16 +65,18 @@ int br_switchdev_set_port_flag(struct net_bridge_port *p,
struct switchdev_attr attr = { struct switchdev_attr attr = {
.orig_dev = p->dev, .orig_dev = p->dev,
.id = SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS, .id = SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS,
.u.brport_flags = mask,
}; };
struct switchdev_notifier_port_attr_info info = { struct switchdev_notifier_port_attr_info info = {
.attr = &attr, .attr = &attr,
}; };
int err; int err;
if (mask & ~BR_PORT_FLAGS_HW_OFFLOAD) mask &= BR_PORT_FLAGS_HW_OFFLOAD;
if (!mask)
return 0; return 0;
attr.u.brport_flags = mask;
/* We run from atomic context here */ /* We run from atomic context here */
err = call_switchdev_notifiers(SWITCHDEV_PORT_ATTR_SET, p->dev, err = call_switchdev_notifiers(SWITCHDEV_PORT_ATTR_SET, p->dev,
&info.info, NULL); &info.info, NULL);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment