Commit 2836882f authored by Toshiaki Makita's avatar Toshiaki Makita Committed by David S. Miller

bridge: Fix the way to insert new local fdb entries in br_fdb_changeaddr

Since commit bc9a25d2 ("bridge: Add vlan support for local fdb entries"),
br_fdb_changeaddr() has inserted a new local fdb entry only if it can
find old one. But if we have two ports where they have the same address
or user has deleted a local entry, there will be no entry for one of the
ports.

Example of problematic case:
  ip link set eth0 address aa:bb:cc:dd:ee:ff
  ip link set eth1 address aa:bb:cc:dd:ee:ff
  brctl addif br0 eth0
  brctl addif br0 eth1 # eth1 will not have a local entry due to dup.
  ip link set eth1 address 12:34:56:78:90:ab
Then, the new entry for the address 12:34:56:78:90:ab will not be
created, and the bridge device will not be able to communicate.

Insert new entries regardless of whether we can find old entries or not.
Signed-off-by: default avatarToshiaki Makita <makita.toshiaki@lab.ntt.co.jp>
Acked-by: default avatarVlad Yasevich <vyasevic@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a5642ab4
...@@ -92,8 +92,10 @@ static void fdb_delete(struct net_bridge *br, struct net_bridge_fdb_entry *f) ...@@ -92,8 +92,10 @@ static void fdb_delete(struct net_bridge *br, struct net_bridge_fdb_entry *f)
void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr) void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr)
{ {
struct net_bridge *br = p->br; struct net_bridge *br = p->br;
bool no_vlan = (nbp_get_vlan_info(p) == NULL) ? true : false; struct net_port_vlans *pv = nbp_get_vlan_info(p);
bool no_vlan = !pv;
int i; int i;
u16 vid;
spin_lock_bh(&br->hash_lock); spin_lock_bh(&br->hash_lock);
...@@ -114,28 +116,37 @@ void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr) ...@@ -114,28 +116,37 @@ void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr)
f->addr.addr) && f->addr.addr) &&
nbp_vlan_find(op, vid)) { nbp_vlan_find(op, vid)) {
f->dst = op; f->dst = op;
goto insert; goto skip_delete;
} }
} }
/* delete old one */ /* delete old one */
fdb_delete(br, f); fdb_delete(br, f);
insert: skip_delete:
/* insert new address, may fail if invalid
* address or dup.
*/
fdb_insert(br, p, newaddr, vid);
/* if this port has no vlan information /* if this port has no vlan information
* configured, we can safely be done at * configured, we can safely be done at
* this point. * this point.
*/ */
if (no_vlan) if (no_vlan)
goto done; goto insert;
} }
} }
} }
insert:
/* insert new address, may fail if invalid address or dup. */
fdb_insert(br, p, newaddr, 0);
if (no_vlan)
goto done;
/* Now add entries for every VLAN configured on the port.
* This function runs under RTNL so the bitmap will not change
* from under us.
*/
for_each_set_bit(vid, pv->vlan_bitmap, VLAN_N_VID)
fdb_insert(br, p, newaddr, vid);
done: done:
spin_unlock_bh(&br->hash_lock); spin_unlock_bh(&br->hash_lock);
} }
......
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