Skip to content

Commit 6ef7b8a

Browse files
Vlad Yasevichdavem330
authored andcommitted
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 4543fbe. 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: Andrey 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: Vlad Yasevich <vyasevic@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent a1d0cd8 commit 6ef7b8a

File tree

1 file changed

+10
-8
lines changed

1 file changed

+10
-8
lines changed

net/core/dev_addr_lists.c

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ static int __hw_addr_create_ex(struct netdev_hw_addr_list *list,
3838
ha->type = addr_type;
3939
ha->refcount = 1;
4040
ha->global_use = global;
41-
ha->synced = sync;
41+
ha->synced = sync ? 1 : 0;
4242
ha->sync_cnt = 0;
4343
list_add_tail_rcu(&ha->list, &list->list);
4444
list->count++;
@@ -48,7 +48,8 @@ static int __hw_addr_create_ex(struct netdev_hw_addr_list *list,
4848

4949
static int __hw_addr_add_ex(struct netdev_hw_addr_list *list,
5050
const unsigned char *addr, int addr_len,
51-
unsigned char addr_type, bool global, bool sync)
51+
unsigned char addr_type, bool global, bool sync,
52+
int sync_count)
5253
{
5354
struct netdev_hw_addr *ha;
5455

@@ -66,10 +67,10 @@ static int __hw_addr_add_ex(struct netdev_hw_addr_list *list,
6667
ha->global_use = true;
6768
}
6869
if (sync) {
69-
if (ha->synced)
70+
if (ha->synced && sync_count)
7071
return -EEXIST;
7172
else
72-
ha->synced = true;
73+
ha->synced++;
7374
}
7475
ha->refcount++;
7576
return 0;
@@ -84,7 +85,8 @@ static int __hw_addr_add(struct netdev_hw_addr_list *list,
8485
const unsigned char *addr, int addr_len,
8586
unsigned char addr_type)
8687
{
87-
return __hw_addr_add_ex(list, addr, addr_len, addr_type, false, false);
88+
return __hw_addr_add_ex(list, addr, addr_len, addr_type, false, false,
89+
0);
8890
}
8991

9092
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,
101103
ha->global_use = false;
102104

103105
if (sync)
104-
ha->synced = false;
106+
ha->synced--;
105107

106108
if (--ha->refcount)
107109
return 0;
@@ -139,7 +141,7 @@ static int __hw_addr_sync_one(struct netdev_hw_addr_list *to_list,
139141
int err;
140142

141143
err = __hw_addr_add_ex(to_list, ha->addr, addr_len, ha->type,
142-
false, true);
144+
false, true, ha->sync_cnt);
143145
if (err && err != -EEXIST)
144146
return err;
145147

@@ -581,7 +583,7 @@ static int __dev_mc_add(struct net_device *dev, const unsigned char *addr,
581583

582584
netif_addr_lock_bh(dev);
583585
err = __hw_addr_add_ex(&dev->mc, addr, dev->addr_len,
584-
NETDEV_HW_ADDR_T_MULTICAST, global, false);
586+
NETDEV_HW_ADDR_T_MULTICAST, global, false, 0);
585587
if (!err)
586588
__dev_set_rx_mode(dev);
587589
netif_addr_unlock_bh(dev);

0 commit comments

Comments
 (0)