Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 202928
b: refs/heads/master
c: 91d2c34
h: refs/heads/master
v: v3
  • Loading branch information
Herbert Xu authored and David S. Miller committed Jun 15, 2010
1 parent 0c294ba commit e4ed8e8
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 85 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: c18370f5b2949d9cca519355f33690b75e1e7c8b
refs/heads/master: 91d2c34a4eed32876ca333b0ca44f3bc56645805
108 changes: 61 additions & 47 deletions trunk/net/bridge/br_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
skb_pull(skb, ETH_HLEN);

if (is_multicast_ether_addr(dest)) {
if (unlikely(netpoll_tx_running(dev))) {
br_flood_deliver(br, skb);
goto out;
}
if (br_multicast_rcv(br, NULL, skb))
goto out;

Expand Down Expand Up @@ -199,72 +203,81 @@ static int br_set_tx_csum(struct net_device *dev, u32 data)
}

#ifdef CONFIG_NET_POLL_CONTROLLER
static bool br_devices_support_netpoll(struct net_bridge *br)
static void br_poll_controller(struct net_device *br_dev)
{
struct net_bridge_port *p;
bool ret = true;
int count = 0;
unsigned long flags;

spin_lock_irqsave(&br->lock, flags);
list_for_each_entry(p, &br->port_list, list) {
count++;
if ((p->dev->priv_flags & IFF_DISABLE_NETPOLL) ||
!p->dev->netdev_ops->ndo_poll_controller)
ret = false;
}
spin_unlock_irqrestore(&br->lock, flags);
return count != 0 && ret;
}

static void br_poll_controller(struct net_device *br_dev)
static void br_netpoll_cleanup(struct net_device *dev)
{
struct netpoll *np = br_dev->npinfo->netpoll;
struct net_bridge *br = netdev_priv(dev);
struct net_bridge_port *p, *n;

if (np->real_dev != br_dev)
netpoll_poll_dev(np->real_dev);
list_for_each_entry_safe(p, n, &br->port_list, list) {
br_netpoll_disable(p);
}
}

void br_netpoll_cleanup(struct net_device *dev)
static int br_netpoll_setup(struct net_device *dev, struct netpoll_info *ni)
{
struct net_bridge *br = netdev_priv(dev);
struct net_bridge_port *p, *n;
const struct net_device_ops *ops;
int err = 0;

list_for_each_entry_safe(p, n, &br->port_list, list) {
if (p->dev) {
ops = p->dev->netdev_ops;
if (ops->ndo_netpoll_cleanup)
ops->ndo_netpoll_cleanup(p->dev);
else
p->dev->npinfo = NULL;
}
if (!p->dev)
continue;

err = br_netpoll_enable(p);
if (err)
goto fail;
}

out:
return err;

fail:
br_netpoll_cleanup(dev);
goto out;
}

void br_netpoll_disable(struct net_bridge *br,
struct net_device *dev)
int br_netpoll_enable(struct net_bridge_port *p)
{
if (br_devices_support_netpoll(br))
br->dev->priv_flags &= ~IFF_DISABLE_NETPOLL;
if (dev->netdev_ops->ndo_netpoll_cleanup)
dev->netdev_ops->ndo_netpoll_cleanup(dev);
else
dev->npinfo = NULL;
struct netpoll *np;
int err = 0;

np = kzalloc(sizeof(*p->np), GFP_KERNEL);
err = -ENOMEM;
if (!np)
goto out;

np->dev = p->dev;

err = __netpoll_setup(np);
if (err) {
kfree(np);
goto out;
}

p->np = np;

out:
return err;
}

void br_netpoll_enable(struct net_bridge *br,
struct net_device *dev)
void br_netpoll_disable(struct net_bridge_port *p)
{
if (br_devices_support_netpoll(br)) {
br->dev->priv_flags &= ~IFF_DISABLE_NETPOLL;
if (br->dev->npinfo)
dev->npinfo = br->dev->npinfo;
} else if (!(br->dev->priv_flags & IFF_DISABLE_NETPOLL)) {
br->dev->priv_flags |= IFF_DISABLE_NETPOLL;
br_info(br,"new device %s does not support netpoll (disabling)",
dev->name);
}
struct netpoll *np = p->np;

if (!np)
return;

p->np = NULL;

/* Wait for transmitting packets to finish before freeing. */
synchronize_rcu_bh();

__netpoll_cleanup(np);
kfree(np);
}

#endif
Expand Down Expand Up @@ -293,6 +306,7 @@ static const struct net_device_ops br_netdev_ops = {
.ndo_change_mtu = br_change_mtu,
.ndo_do_ioctl = br_dev_ioctl,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_netpoll_setup = br_netpoll_setup,
.ndo_netpoll_cleanup = br_netpoll_cleanup,
.ndo_poll_controller = br_poll_controller,
#endif
Expand Down
34 changes: 12 additions & 22 deletions trunk/net/bridge/br_forward.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,7 @@ int br_dev_queue_push_xmit(struct sk_buff *skb)
kfree_skb(skb);
else {
skb_push(skb, ETH_HLEN);

#ifdef CONFIG_NET_POLL_CONTROLLER
if (unlikely(skb->dev->priv_flags & IFF_IN_NETPOLL)) {
netpoll_send_skb(skb->dev->npinfo->netpoll, skb);
skb->dev->priv_flags &= ~IFF_IN_NETPOLL;
} else
#endif
dev_queue_xmit(skb);
dev_queue_xmit(skb);
}
}

Expand All @@ -73,23 +66,20 @@ int br_forward_finish(struct sk_buff *skb)

static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
{
#ifdef CONFIG_NET_POLL_CONTROLLER
struct net_bridge *br = to->br;
if (unlikely(br->dev->priv_flags & IFF_IN_NETPOLL)) {
struct netpoll *np;
to->dev->npinfo = skb->dev->npinfo;
np = skb->dev->npinfo->netpoll;
np->real_dev = np->dev = to->dev;
to->dev->priv_flags |= IFF_IN_NETPOLL;
}
#endif
skb->dev = to->dev;

if (unlikely(netpoll_tx_running(to->dev))) {
if (packet_length(skb) > skb->dev->mtu && !skb_is_gso(skb))
kfree_skb(skb);
else {
skb_push(skb, ETH_HLEN);
br_netpoll_send_skb(to, skb);
}
return;
}

NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
br_forward_finish);
#ifdef CONFIG_NET_POLL_CONTROLLER
if (skb->dev->npinfo)
skb->dev->npinfo->netpoll->dev = br->dev;
#endif
}

static void __br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
Expand Down
16 changes: 9 additions & 7 deletions trunk/net/bridge/br_if.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,8 @@ static void del_nbp(struct net_bridge_port *p)
kobject_uevent(&p->kobj, KOBJ_REMOVE);
kobject_del(&p->kobj);

br_netpoll_disable(br, dev);
br_netpoll_disable(p);

call_rcu(&p->rcu, destroy_nbp_rcu);
}

Expand All @@ -168,8 +169,6 @@ static void del_br(struct net_bridge *br, struct list_head *head)
del_nbp(p);
}

br_netpoll_cleanup(br->dev);

del_timer_sync(&br->gc_timer);

br_sysfs_delbr(br->dev);
Expand Down Expand Up @@ -429,11 +428,14 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
if (err)
goto err2;

if (br_netpoll_info(br) && ((err = br_netpoll_enable(p))))
goto err3;

rcu_assign_pointer(dev->br_port, p);

err = netdev_rx_handler_register(dev, br_handle_frame);
if (err)
goto err3;
goto err4;

dev_disable_lro(dev);

Expand All @@ -454,11 +456,11 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)

kobject_uevent(&p->kobj, KOBJ_ADD);

br_netpoll_enable(br, dev);

return 0;
err3:
err4:
rcu_assign_pointer(dev->br_port, NULL);
err3:
sysfs_remove_link(br->ifobj, p->dev->name);
err2:
br_fdb_delete_by_port(br, p, 1);
err1:
Expand Down
46 changes: 38 additions & 8 deletions trunk/net/bridge/br_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include <linux/netdevice.h>
#include <linux/if_bridge.h>
#include <linux/netpoll.h>
#include <net/route.h>

#define BR_HASH_BITS 8
Expand Down Expand Up @@ -143,6 +144,10 @@ struct net_bridge_port
#ifdef CONFIG_SYSFS
char sysfs_name[IFNAMSIZ];
#endif

#ifdef CONFIG_NET_POLL_CONTROLLER
struct netpoll *np;
#endif
};

struct br_cpu_netstats {
Expand Down Expand Up @@ -273,16 +278,41 @@ extern void br_dev_setup(struct net_device *dev);
extern netdev_tx_t br_dev_xmit(struct sk_buff *skb,
struct net_device *dev);
#ifdef CONFIG_NET_POLL_CONTROLLER
extern void br_netpoll_cleanup(struct net_device *dev);
extern void br_netpoll_enable(struct net_bridge *br,
struct net_device *dev);
extern void br_netpoll_disable(struct net_bridge *br,
struct net_device *dev);
static inline struct netpoll_info *br_netpoll_info(struct net_bridge *br)
{
return br->dev->npinfo;
}

static inline void br_netpoll_send_skb(const struct net_bridge_port *p,
struct sk_buff *skb)
{
struct netpoll *np = p->np;

if (np)
netpoll_send_skb(np, skb);
}

extern int br_netpoll_enable(struct net_bridge_port *p);
extern void br_netpoll_disable(struct net_bridge_port *p);
#else
#define br_netpoll_cleanup(br)
#define br_netpoll_enable(br, dev)
#define br_netpoll_disable(br, dev)
static inline struct netpoll_info *br_netpoll_info(struct net_bridge *br)
{
return NULL;
}

static inline void br_netpoll_send_skb(struct net_bridge_port *p,
struct sk_buff *skb)
{
}

static inline int br_netpoll_enable(struct net_bridge_port *p)
{
return 0;
}

static inline void br_netpoll_disable(struct net_bridge_port *p)
{
}
#endif

/* br_fdb.c */
Expand Down

0 comments on commit e4ed8e8

Please sign in to comment.