aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge
diff options
context:
space:
mode:
Diffstat (limited to 'net/bridge')
-rw-r--r--net/bridge/br_device.c108
-rw-r--r--net/bridge/br_forward.c34
-rw-r--r--net/bridge/br_if.c16
-rw-r--r--net/bridge/br_private.h46
4 files changed, 120 insertions, 84 deletions
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index f8cb908db81f..6f3a9279be30 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -47,6 +47,10 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
47 skb_pull(skb, ETH_HLEN); 47 skb_pull(skb, ETH_HLEN);
48 48
49 if (is_multicast_ether_addr(dest)) { 49 if (is_multicast_ether_addr(dest)) {
50 if (unlikely(netpoll_tx_running(dev))) {
51 br_flood_deliver(br, skb);
52 goto out;
53 }
50 if (br_multicast_rcv(br, NULL, skb)) 54 if (br_multicast_rcv(br, NULL, skb))
51 goto out; 55 goto out;
52 56
@@ -199,72 +203,81 @@ static int br_set_tx_csum(struct net_device *dev, u32 data)
199} 203}
200 204
201#ifdef CONFIG_NET_POLL_CONTROLLER 205#ifdef CONFIG_NET_POLL_CONTROLLER
202static bool br_devices_support_netpoll(struct net_bridge *br) 206static void br_poll_controller(struct net_device *br_dev)
203{ 207{
204 struct net_bridge_port *p;
205 bool ret = true;
206 int count = 0;
207 unsigned long flags;
208
209 spin_lock_irqsave(&br->lock, flags);
210 list_for_each_entry(p, &br->port_list, list) {
211 count++;
212 if ((p->dev->priv_flags & IFF_DISABLE_NETPOLL) ||
213 !p->dev->netdev_ops->ndo_poll_controller)
214 ret = false;
215 }
216 spin_unlock_irqrestore(&br->lock, flags);
217 return count != 0 && ret;
218} 208}
219 209
220static void br_poll_controller(struct net_device *br_dev) 210static void br_netpoll_cleanup(struct net_device *dev)
221{ 211{
222 struct netpoll *np = br_dev->npinfo->netpoll; 212 struct net_bridge *br = netdev_priv(dev);
213 struct net_bridge_port *p, *n;
223 214
224 if (np->real_dev != br_dev) 215 list_for_each_entry_safe(p, n, &br->port_list, list) {
225 netpoll_poll_dev(np->real_dev); 216 br_netpoll_disable(p);
217 }
226} 218}
227 219
228void br_netpoll_cleanup(struct net_device *dev) 220static int br_netpoll_setup(struct net_device *dev, struct netpoll_info *ni)
229{ 221{
230 struct net_bridge *br = netdev_priv(dev); 222 struct net_bridge *br = netdev_priv(dev);
231 struct net_bridge_port *p, *n; 223 struct net_bridge_port *p, *n;
232 const struct net_device_ops *ops; 224 int err = 0;
233 225
234 list_for_each_entry_safe(p, n, &br->port_list, list) { 226 list_for_each_entry_safe(p, n, &br->port_list, list) {
235 if (p->dev) { 227 if (!p->dev)
236 ops = p->dev->netdev_ops; 228 continue;
237 if (ops->ndo_netpoll_cleanup) 229
238 ops->ndo_netpoll_cleanup(p->dev); 230 err = br_netpoll_enable(p);
239 else 231 if (err)
240 p->dev->npinfo = NULL; 232 goto fail;
241 }
242 } 233 }
234
235out:
236 return err;
237
238fail:
239 br_netpoll_cleanup(dev);
240 goto out;
243} 241}
244 242
245void br_netpoll_disable(struct net_bridge *br, 243int br_netpoll_enable(struct net_bridge_port *p)
246 struct net_device *dev)
247{ 244{
248 if (br_devices_support_netpoll(br)) 245 struct netpoll *np;
249 br->dev->priv_flags &= ~IFF_DISABLE_NETPOLL; 246 int err = 0;
250 if (dev->netdev_ops->ndo_netpoll_cleanup) 247
251 dev->netdev_ops->ndo_netpoll_cleanup(dev); 248 np = kzalloc(sizeof(*p->np), GFP_KERNEL);
252 else 249 err = -ENOMEM;
253 dev->npinfo = NULL; 250 if (!np)
251 goto out;
252
253 np->dev = p->dev;
254
255 err = __netpoll_setup(np);
256 if (err) {
257 kfree(np);
258 goto out;
259 }
260
261 p->np = np;
262
263out:
264 return err;
254} 265}
255 266
256void br_netpoll_enable(struct net_bridge *br, 267void br_netpoll_disable(struct net_bridge_port *p)
257 struct net_device *dev)
258{ 268{
259 if (br_devices_support_netpoll(br)) { 269 struct netpoll *np = p->np;
260 br->dev->priv_flags &= ~IFF_DISABLE_NETPOLL; 270
261 if (br->dev->npinfo) 271 if (!np)
262 dev->npinfo = br->dev->npinfo; 272 return;
263 } else if (!(br->dev->priv_flags & IFF_DISABLE_NETPOLL)) { 273
264 br->dev->priv_flags |= IFF_DISABLE_NETPOLL; 274 p->np = NULL;
265 br_info(br,"new device %s does not support netpoll (disabling)", 275
266 dev->name); 276 /* Wait for transmitting packets to finish before freeing. */
267 } 277 synchronize_rcu_bh();
278
279 __netpoll_cleanup(np);
280 kfree(np);
268} 281}
269 282
270#endif 283#endif
@@ -293,6 +306,7 @@ static const struct net_device_ops br_netdev_ops = {
293 .ndo_change_mtu = br_change_mtu, 306 .ndo_change_mtu = br_change_mtu,
294 .ndo_do_ioctl = br_dev_ioctl, 307 .ndo_do_ioctl = br_dev_ioctl,
295#ifdef CONFIG_NET_POLL_CONTROLLER 308#ifdef CONFIG_NET_POLL_CONTROLLER
309 .ndo_netpoll_setup = br_netpoll_setup,
296 .ndo_netpoll_cleanup = br_netpoll_cleanup, 310 .ndo_netpoll_cleanup = br_netpoll_cleanup,
297 .ndo_poll_controller = br_poll_controller, 311 .ndo_poll_controller = br_poll_controller,
298#endif 312#endif
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index a98ef1393097..6e97711fd2c5 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -50,14 +50,7 @@ int br_dev_queue_push_xmit(struct sk_buff *skb)
50 kfree_skb(skb); 50 kfree_skb(skb);
51 else { 51 else {
52 skb_push(skb, ETH_HLEN); 52 skb_push(skb, ETH_HLEN);
53 53 dev_queue_xmit(skb);
54#ifdef CONFIG_NET_POLL_CONTROLLER
55 if (unlikely(skb->dev->priv_flags & IFF_IN_NETPOLL)) {
56 netpoll_send_skb(skb->dev->npinfo->netpoll, skb);
57 skb->dev->priv_flags &= ~IFF_IN_NETPOLL;
58 } else
59#endif
60 dev_queue_xmit(skb);
61 } 54 }
62 } 55 }
63 56
@@ -73,23 +66,20 @@ int br_forward_finish(struct sk_buff *skb)
73 66
74static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb) 67static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
75{ 68{
76#ifdef CONFIG_NET_POLL_CONTROLLER
77 struct net_bridge *br = to->br;
78 if (unlikely(br->dev->priv_flags & IFF_IN_NETPOLL)) {
79 struct netpoll *np;
80 to->dev->npinfo = skb->dev->npinfo;
81 np = skb->dev->npinfo->netpoll;
82 np->real_dev = np->dev = to->dev;
83 to->dev->priv_flags |= IFF_IN_NETPOLL;
84 }
85#endif
86 skb->dev = to->dev; 69 skb->dev = to->dev;
70
71 if (unlikely(netpoll_tx_running(to->dev))) {
72 if (packet_length(skb) > skb->dev->mtu && !skb_is_gso(skb))
73 kfree_skb(skb);
74 else {
75 skb_push(skb, ETH_HLEN);
76 br_netpoll_send_skb(to, skb);
77 }
78 return;
79 }
80
87 NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, 81 NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
88 br_forward_finish); 82 br_forward_finish);
89#ifdef CONFIG_NET_POLL_CONTROLLER
90 if (skb->dev->npinfo)
91 skb->dev->npinfo->netpoll->dev = br->dev;
92#endif
93} 83}
94 84
95static void __br_forward(const struct net_bridge_port *to, struct sk_buff *skb) 85static void __br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index d9242342837e..97ac9da4d76c 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -155,7 +155,8 @@ static void del_nbp(struct net_bridge_port *p)
155 kobject_uevent(&p->kobj, KOBJ_REMOVE); 155 kobject_uevent(&p->kobj, KOBJ_REMOVE);
156 kobject_del(&p->kobj); 156 kobject_del(&p->kobj);
157 157
158 br_netpoll_disable(br, dev); 158 br_netpoll_disable(p);
159
159 call_rcu(&p->rcu, destroy_nbp_rcu); 160 call_rcu(&p->rcu, destroy_nbp_rcu);
160} 161}
161 162
@@ -168,8 +169,6 @@ static void del_br(struct net_bridge *br, struct list_head *head)
168 del_nbp(p); 169 del_nbp(p);
169 } 170 }
170 171
171 br_netpoll_cleanup(br->dev);
172
173 del_timer_sync(&br->gc_timer); 172 del_timer_sync(&br->gc_timer);
174 173
175 br_sysfs_delbr(br->dev); 174 br_sysfs_delbr(br->dev);
@@ -429,11 +428,14 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
429 if (err) 428 if (err)
430 goto err2; 429 goto err2;
431 430
431 if (br_netpoll_info(br) && ((err = br_netpoll_enable(p))))
432 goto err3;
433
432 rcu_assign_pointer(dev->br_port, p); 434 rcu_assign_pointer(dev->br_port, p);
433 435
434 err = netdev_rx_handler_register(dev, br_handle_frame); 436 err = netdev_rx_handler_register(dev, br_handle_frame);
435 if (err) 437 if (err)
436 goto err3; 438 goto err4;
437 439
438 dev_disable_lro(dev); 440 dev_disable_lro(dev);
439 441
@@ -454,11 +456,11 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
454 456
455 kobject_uevent(&p->kobj, KOBJ_ADD); 457 kobject_uevent(&p->kobj, KOBJ_ADD);
456 458
457 br_netpoll_enable(br, dev);
458
459 return 0; 459 return 0;
460err3: 460err4:
461 rcu_assign_pointer(dev->br_port, NULL); 461 rcu_assign_pointer(dev->br_port, NULL);
462err3:
463 sysfs_remove_link(br->ifobj, p->dev->name);
462err2: 464err2:
463 br_fdb_delete_by_port(br, p, 1); 465 br_fdb_delete_by_port(br, p, 1);
464err1: 466err1:
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index c83519b555bb..0f5394c4f2f1 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -15,6 +15,7 @@
15 15
16#include <linux/netdevice.h> 16#include <linux/netdevice.h>
17#include <linux/if_bridge.h> 17#include <linux/if_bridge.h>
18#include <linux/netpoll.h>
18#include <net/route.h> 19#include <net/route.h>
19 20
20#define BR_HASH_BITS 8 21#define BR_HASH_BITS 8
@@ -143,6 +144,10 @@ struct net_bridge_port
143#ifdef CONFIG_SYSFS 144#ifdef CONFIG_SYSFS
144 char sysfs_name[IFNAMSIZ]; 145 char sysfs_name[IFNAMSIZ];
145#endif 146#endif
147
148#ifdef CONFIG_NET_POLL_CONTROLLER
149 struct netpoll *np;
150#endif
146}; 151};
147 152
148struct br_cpu_netstats { 153struct br_cpu_netstats {
@@ -273,16 +278,41 @@ extern void br_dev_setup(struct net_device *dev);
273extern netdev_tx_t br_dev_xmit(struct sk_buff *skb, 278extern netdev_tx_t br_dev_xmit(struct sk_buff *skb,
274 struct net_device *dev); 279 struct net_device *dev);
275#ifdef CONFIG_NET_POLL_CONTROLLER 280#ifdef CONFIG_NET_POLL_CONTROLLER
276extern void br_netpoll_cleanup(struct net_device *dev); 281static inline struct netpoll_info *br_netpoll_info(struct net_bridge *br)
277extern void br_netpoll_enable(struct net_bridge *br, 282{
278 struct net_device *dev); 283 return br->dev->npinfo;
279extern void br_netpoll_disable(struct net_bridge *br, 284}
280 struct net_device *dev); 285
286static inline void br_netpoll_send_skb(const struct net_bridge_port *p,
287 struct sk_buff *skb)
288{
289 struct netpoll *np = p->np;
290
291 if (np)
292 netpoll_send_skb(np, skb);
293}
294
295extern int br_netpoll_enable(struct net_bridge_port *p);
296extern void br_netpoll_disable(struct net_bridge_port *p);
281#else 297#else
282#define br_netpoll_cleanup(br) 298static inline struct netpoll_info *br_netpoll_info(struct net_bridge *br)
283#define br_netpoll_enable(br, dev) 299{
284#define br_netpoll_disable(br, dev) 300 return NULL;
301}
302
303static inline void br_netpoll_send_skb(struct net_bridge_port *p,
304 struct sk_buff *skb)
305{
306}
285 307
308static inline int br_netpoll_enable(struct net_bridge_port *p)
309{
310 return 0;
311}
312
313static inline void br_netpoll_disable(struct net_bridge_port *p)
314{
315}
286#endif 316#endif
287 317
288/* br_fdb.c */ 318/* br_fdb.c */