diff options
| -rw-r--r-- | net/bridge/br_device.c | 108 | ||||
| -rw-r--r-- | net/bridge/br_forward.c | 34 | ||||
| -rw-r--r-- | net/bridge/br_if.c | 16 | ||||
| -rw-r--r-- | net/bridge/br_private.h | 46 |
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 |
| 202 | static bool br_devices_support_netpoll(struct net_bridge *br) | 206 | static 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 | ||
| 220 | static void br_poll_controller(struct net_device *br_dev) | 210 | static 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 | ||
| 228 | void br_netpoll_cleanup(struct net_device *dev) | 220 | static 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 | |||
| 235 | out: | ||
| 236 | return err; | ||
| 237 | |||
| 238 | fail: | ||
| 239 | br_netpoll_cleanup(dev); | ||
| 240 | goto out; | ||
| 243 | } | 241 | } |
| 244 | 242 | ||
| 245 | void br_netpoll_disable(struct net_bridge *br, | 243 | int 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 | |||
| 263 | out: | ||
| 264 | return err; | ||
| 254 | } | 265 | } |
| 255 | 266 | ||
| 256 | void br_netpoll_enable(struct net_bridge *br, | 267 | void 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 | ||
| 74 | static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb) | 67 | static 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 | ||
| 95 | static void __br_forward(const struct net_bridge_port *to, struct sk_buff *skb) | 85 | static 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; |
| 460 | err3: | 460 | err4: |
| 461 | rcu_assign_pointer(dev->br_port, NULL); | 461 | rcu_assign_pointer(dev->br_port, NULL); |
| 462 | err3: | ||
| 463 | sysfs_remove_link(br->ifobj, p->dev->name); | ||
| 462 | err2: | 464 | err2: |
| 463 | br_fdb_delete_by_port(br, p, 1); | 465 | br_fdb_delete_by_port(br, p, 1); |
| 464 | err1: | 466 | err1: |
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 | ||
| 148 | struct br_cpu_netstats { | 153 | struct br_cpu_netstats { |
| @@ -273,16 +278,41 @@ extern void br_dev_setup(struct net_device *dev); | |||
| 273 | extern netdev_tx_t br_dev_xmit(struct sk_buff *skb, | 278 | extern 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 |
| 276 | extern void br_netpoll_cleanup(struct net_device *dev); | 281 | static inline struct netpoll_info *br_netpoll_info(struct net_bridge *br) |
| 277 | extern void br_netpoll_enable(struct net_bridge *br, | 282 | { |
| 278 | struct net_device *dev); | 283 | return br->dev->npinfo; |
| 279 | extern void br_netpoll_disable(struct net_bridge *br, | 284 | } |
| 280 | struct net_device *dev); | 285 | |
| 286 | static 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 | |||
| 295 | extern int br_netpoll_enable(struct net_bridge_port *p); | ||
| 296 | extern void br_netpoll_disable(struct net_bridge_port *p); | ||
| 281 | #else | 297 | #else |
| 282 | #define br_netpoll_cleanup(br) | 298 | static 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 | |||
| 303 | static inline void br_netpoll_send_skb(struct net_bridge_port *p, | ||
| 304 | struct sk_buff *skb) | ||
| 305 | { | ||
| 306 | } | ||
| 285 | 307 | ||
| 308 | static inline int br_netpoll_enable(struct net_bridge_port *p) | ||
| 309 | { | ||
| 310 | return 0; | ||
| 311 | } | ||
| 312 | |||
| 313 | static 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 */ |
