提交 6ef7b8a2 编写于 作者: V Vlad Yasevich 提交者: David S. Miller

net: Correctly sync addresses from multiple sources to single device

When we have multiple devices attempting to sync the same address
to a single destination, each device should be permitted to sync
it once.  To accomplish this, pass the 'sync_cnt' of the source
address when adding the addresss to the lower device.  'sync_cnt'
tracks how many time a given address has been succefully synced.
This way, we know that if the 'sync_cnt' passed in is 0, we should
sync this address.

Also, turn 'synced' member back into the counter as was originally
done in
   commit 4543fbef.
   net: count hw_addr syncs so that unsync works properly.
It tracks how many time a given address has been added via a
'sync' operation.  For every successfull 'sync' the counter is
incremented, and for ever 'unsync', the counter is decremented.
This makes sure that the address will be properly removed from
the the lower device when all the upper devices have removed it.
Reported-by: NAndrey Dmitrov <andrey.dmitrov@oktetlabs.ru>
CC: Andrey Dmitrov <andrey.dmitrov@oktetlabs.ru>
CC: Alexandra N. Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
CC: Konstantin Ushakov <Konstantin.Ushakov@oktetlabs.ru>
Signed-off-by: NVlad Yasevich <vyasevic@redhat.com>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 a1d0cd8e
...@@ -38,7 +38,7 @@ static int __hw_addr_create_ex(struct netdev_hw_addr_list *list, ...@@ -38,7 +38,7 @@ static int __hw_addr_create_ex(struct netdev_hw_addr_list *list,
ha->type = addr_type; ha->type = addr_type;
ha->refcount = 1; ha->refcount = 1;
ha->global_use = global; ha->global_use = global;
ha->synced = sync; ha->synced = sync ? 1 : 0;
ha->sync_cnt = 0; ha->sync_cnt = 0;
list_add_tail_rcu(&ha->list, &list->list); list_add_tail_rcu(&ha->list, &list->list);
list->count++; list->count++;
...@@ -48,7 +48,8 @@ static int __hw_addr_create_ex(struct netdev_hw_addr_list *list, ...@@ -48,7 +48,8 @@ static int __hw_addr_create_ex(struct netdev_hw_addr_list *list,
static int __hw_addr_add_ex(struct netdev_hw_addr_list *list, static int __hw_addr_add_ex(struct netdev_hw_addr_list *list,
const unsigned char *addr, int addr_len, const unsigned char *addr, int addr_len,
unsigned char addr_type, bool global, bool sync) unsigned char addr_type, bool global, bool sync,
int sync_count)
{ {
struct netdev_hw_addr *ha; struct netdev_hw_addr *ha;
...@@ -66,10 +67,10 @@ static int __hw_addr_add_ex(struct netdev_hw_addr_list *list, ...@@ -66,10 +67,10 @@ static int __hw_addr_add_ex(struct netdev_hw_addr_list *list,
ha->global_use = true; ha->global_use = true;
} }
if (sync) { if (sync) {
if (ha->synced) if (ha->synced && sync_count)
return -EEXIST; return -EEXIST;
else else
ha->synced = true; ha->synced++;
} }
ha->refcount++; ha->refcount++;
return 0; return 0;
...@@ -84,7 +85,8 @@ static int __hw_addr_add(struct netdev_hw_addr_list *list, ...@@ -84,7 +85,8 @@ static int __hw_addr_add(struct netdev_hw_addr_list *list,
const unsigned char *addr, int addr_len, const unsigned char *addr, int addr_len,
unsigned char addr_type) unsigned char addr_type)
{ {
return __hw_addr_add_ex(list, addr, addr_len, addr_type, false, false); return __hw_addr_add_ex(list, addr, addr_len, addr_type, false, false,
0);
} }
static int __hw_addr_del_entry(struct netdev_hw_addr_list *list, static int __hw_addr_del_entry(struct netdev_hw_addr_list *list,
...@@ -101,7 +103,7 @@ static int __hw_addr_del_entry(struct netdev_hw_addr_list *list, ...@@ -101,7 +103,7 @@ static int __hw_addr_del_entry(struct netdev_hw_addr_list *list,
ha->global_use = false; ha->global_use = false;
if (sync) if (sync)
ha->synced = false; ha->synced--;
if (--ha->refcount) if (--ha->refcount)
return 0; return 0;
...@@ -139,7 +141,7 @@ static int __hw_addr_sync_one(struct netdev_hw_addr_list *to_list, ...@@ -139,7 +141,7 @@ static int __hw_addr_sync_one(struct netdev_hw_addr_list *to_list,
int err; int err;
err = __hw_addr_add_ex(to_list, ha->addr, addr_len, ha->type, err = __hw_addr_add_ex(to_list, ha->addr, addr_len, ha->type,
false, true); false, true, ha->sync_cnt);
if (err && err != -EEXIST) if (err && err != -EEXIST)
return err; return err;
...@@ -581,7 +583,7 @@ static int __dev_mc_add(struct net_device *dev, const unsigned char *addr, ...@@ -581,7 +583,7 @@ static int __dev_mc_add(struct net_device *dev, const unsigned char *addr,
netif_addr_lock_bh(dev); netif_addr_lock_bh(dev);
err = __hw_addr_add_ex(&dev->mc, addr, dev->addr_len, err = __hw_addr_add_ex(&dev->mc, addr, dev->addr_len,
NETDEV_HW_ADDR_T_MULTICAST, global, false); NETDEV_HW_ADDR_T_MULTICAST, global, false, 0);
if (!err) if (!err)
__dev_set_rx_mode(dev); __dev_set_rx_mode(dev);
netif_addr_unlock_bh(dev); netif_addr_unlock_bh(dev);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册