mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-07-08 15:33:47 +00:00
[NET]: dev_mcast: add multicast list synchronization helpers
The method drivers currently use to synchronize multicast lists is not very pretty: - walk the multicast list - search each entry on a copy of the previous list - if new add to lower device - walk the copy of the previous list - search each entry on the current list - if removed delete from lower device - copy entire list This patch adds a new field to struct dev_addr_list to store the synchronization state and adds two helper functions for synchronization and cleanup. Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
24023451c8
commit
a0a400d79e
2 changed files with 78 additions and 0 deletions
|
@ -190,6 +190,7 @@ struct dev_addr_list
|
||||||
struct dev_addr_list *next;
|
struct dev_addr_list *next;
|
||||||
u8 da_addr[MAX_ADDR_LEN];
|
u8 da_addr[MAX_ADDR_LEN];
|
||||||
u8 da_addrlen;
|
u8 da_addrlen;
|
||||||
|
u8 da_synced;
|
||||||
int da_users;
|
int da_users;
|
||||||
int da_gusers;
|
int da_gusers;
|
||||||
};
|
};
|
||||||
|
@ -1103,6 +1104,8 @@ extern int dev_unicast_delete(struct net_device *dev, void *addr, int alen);
|
||||||
extern int dev_unicast_add(struct net_device *dev, void *addr, int alen);
|
extern int dev_unicast_add(struct net_device *dev, void *addr, int alen);
|
||||||
extern int dev_mc_delete(struct net_device *dev, void *addr, int alen, int all);
|
extern int dev_mc_delete(struct net_device *dev, void *addr, int alen, int all);
|
||||||
extern int dev_mc_add(struct net_device *dev, void *addr, int alen, int newonly);
|
extern int dev_mc_add(struct net_device *dev, void *addr, int alen, int newonly);
|
||||||
|
extern int dev_mc_sync(struct net_device *to, struct net_device *from);
|
||||||
|
extern void dev_mc_unsync(struct net_device *to, struct net_device *from);
|
||||||
extern void dev_mc_discard(struct net_device *dev);
|
extern void dev_mc_discard(struct net_device *dev);
|
||||||
extern int __dev_addr_delete(struct dev_addr_list **list, int *count, void *addr, int alen, int all);
|
extern int __dev_addr_delete(struct dev_addr_list **list, int *count, void *addr, int alen, int all);
|
||||||
extern int __dev_addr_add(struct dev_addr_list **list, int *count, void *addr, int alen, int newonly);
|
extern int __dev_addr_add(struct dev_addr_list **list, int *count, void *addr, int alen, int newonly);
|
||||||
|
|
|
@ -102,6 +102,81 @@ int dev_mc_add(struct net_device *dev, void *addr, int alen, int glbl)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dev_mc_sync - Synchronize device's multicast list to another device
|
||||||
|
* @to: destination device
|
||||||
|
* @from: source device
|
||||||
|
*
|
||||||
|
* Add newly added addresses to the destination device and release
|
||||||
|
* addresses that have no users left. The source device must be
|
||||||
|
* locked by netif_tx_lock_bh.
|
||||||
|
*
|
||||||
|
* This function is intended to be called from the dev->set_multicast_list
|
||||||
|
* function of layered software devices.
|
||||||
|
*/
|
||||||
|
int dev_mc_sync(struct net_device *to, struct net_device *from)
|
||||||
|
{
|
||||||
|
struct dev_addr_list *da;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
netif_tx_lock_bh(to);
|
||||||
|
for (da = from->mc_list; da != NULL; da = da->next) {
|
||||||
|
if (!da->da_synced) {
|
||||||
|
err = __dev_addr_add(&to->mc_list, &to->mc_count,
|
||||||
|
da->da_addr, da->da_addrlen, 0);
|
||||||
|
if (err < 0)
|
||||||
|
break;
|
||||||
|
da->da_synced = 1;
|
||||||
|
da->da_users++;
|
||||||
|
} else if (da->da_users == 1) {
|
||||||
|
__dev_addr_delete(&to->mc_list, &to->mc_count,
|
||||||
|
da->da_addr, da->da_addrlen, 0);
|
||||||
|
__dev_addr_delete(&from->mc_list, &from->mc_count,
|
||||||
|
da->da_addr, da->da_addrlen, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!err)
|
||||||
|
__dev_set_rx_mode(to);
|
||||||
|
netif_tx_unlock_bh(to);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(dev_mc_sync);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dev_mc_unsync - Remove synchronized addresses from the destination
|
||||||
|
* device
|
||||||
|
* @to: destination device
|
||||||
|
* @from: source device
|
||||||
|
*
|
||||||
|
* Remove all addresses that were added to the destination device by
|
||||||
|
* dev_mc_sync(). This function is intended to be called from the
|
||||||
|
* dev->stop function of layered software devices.
|
||||||
|
*/
|
||||||
|
void dev_mc_unsync(struct net_device *to, struct net_device *from)
|
||||||
|
{
|
||||||
|
struct dev_addr_list *da;
|
||||||
|
|
||||||
|
netif_tx_lock_bh(from);
|
||||||
|
netif_tx_lock_bh(to);
|
||||||
|
|
||||||
|
for (da = from->mc_list; da != NULL; da = da->next) {
|
||||||
|
if (!da->da_synced)
|
||||||
|
continue;
|
||||||
|
__dev_addr_delete(&to->mc_list, &to->mc_count,
|
||||||
|
da->da_addr, da->da_addrlen, 0);
|
||||||
|
da->da_synced = 0;
|
||||||
|
__dev_addr_delete(&from->mc_list, &from->mc_count,
|
||||||
|
da->da_addr, da->da_addrlen, 0);
|
||||||
|
}
|
||||||
|
__dev_set_rx_mode(to);
|
||||||
|
|
||||||
|
netif_tx_unlock_bh(to);
|
||||||
|
netif_tx_unlock_bh(from);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(dev_mc_unsync);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Discard multicast list when a device is downed
|
* Discard multicast list when a device is downed
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue