aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2007-07-14 21:52:02 -0400
committerDavid S. Miller <davem@davemloft.net>2007-07-14 21:52:02 -0400
commita0a400d79e3dd7843e7e81baa3ef2957bdc292d0 (patch)
tree1391190938fb43587967f44f0ab139a2522b4a65 /net
parent24023451c8df726692e2f52288a20870d13b501f (diff)
[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>
Diffstat (limited to 'net')
-rw-r--r--net/core/dev_mcast.c75
1 files changed, 75 insertions, 0 deletions
diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c
index aa38100601fb..235a2a8a0d05 100644
--- a/net/core/dev_mcast.c
+++ b/net/core/dev_mcast.c
@@ -102,6 +102,81 @@ int dev_mc_add(struct net_device *dev, void *addr, int alen, int glbl)
102 return err; 102 return err;
103} 103}
104 104
105/**
106 * dev_mc_sync - Synchronize device's multicast list to another device
107 * @to: destination device
108 * @from: source device
109 *
110 * Add newly added addresses to the destination device and release
111 * addresses that have no users left. The source device must be
112 * locked by netif_tx_lock_bh.
113 *
114 * This function is intended to be called from the dev->set_multicast_list
115 * function of layered software devices.
116 */
117int dev_mc_sync(struct net_device *to, struct net_device *from)
118{
119 struct dev_addr_list *da;
120 int err = 0;
121
122 netif_tx_lock_bh(to);
123 for (da = from->mc_list; da != NULL; da = da->next) {
124 if (!da->da_synced) {
125 err = __dev_addr_add(&to->mc_list, &to->mc_count,
126 da->da_addr, da->da_addrlen, 0);
127 if (err < 0)
128 break;
129 da->da_synced = 1;
130 da->da_users++;
131 } else if (da->da_users == 1) {
132 __dev_addr_delete(&to->mc_list, &to->mc_count,
133 da->da_addr, da->da_addrlen, 0);
134 __dev_addr_delete(&from->mc_list, &from->mc_count,
135 da->da_addr, da->da_addrlen, 0);
136 }
137 }
138 if (!err)
139 __dev_set_rx_mode(to);
140 netif_tx_unlock_bh(to);
141
142 return err;
143}
144EXPORT_SYMBOL(dev_mc_sync);
145
146
147/**
148 * dev_mc_unsync - Remove synchronized addresses from the destination
149 * device
150 * @to: destination device
151 * @from: source device
152 *
153 * Remove all addresses that were added to the destination device by
154 * dev_mc_sync(). This function is intended to be called from the
155 * dev->stop function of layered software devices.
156 */
157void dev_mc_unsync(struct net_device *to, struct net_device *from)
158{
159 struct dev_addr_list *da;
160
161 netif_tx_lock_bh(from);
162 netif_tx_lock_bh(to);
163
164 for (da = from->mc_list; da != NULL; da = da->next) {
165 if (!da->da_synced)
166 continue;
167 __dev_addr_delete(&to->mc_list, &to->mc_count,
168 da->da_addr, da->da_addrlen, 0);
169 da->da_synced = 0;
170 __dev_addr_delete(&from->mc_list, &from->mc_count,
171 da->da_addr, da->da_addrlen, 0);
172 }
173 __dev_set_rx_mode(to);
174
175 netif_tx_unlock_bh(to);
176 netif_tx_unlock_bh(from);
177}
178EXPORT_SYMBOL(dev_mc_unsync);
179
105/* 180/*
106 * Discard multicast list when a device is downed 181 * Discard multicast list when a device is downed
107 */ 182 */