|
@@ -59,6 +59,7 @@
|
|
|
#include <linux/uaccess.h>
|
|
|
#include <linux/errno.h>
|
|
|
#include <linux/netdevice.h>
|
|
|
+#include <linux/netpoll.h>
|
|
|
#include <linux/inetdevice.h>
|
|
|
#include <linux/igmp.h>
|
|
|
#include <linux/etherdevice.h>
|
|
@@ -430,7 +431,18 @@ int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb,
|
|
|
}
|
|
|
|
|
|
skb->priority = 1;
|
|
|
- dev_queue_xmit(skb);
|
|
|
+#ifdef CONFIG_NET_POLL_CONTROLLER
|
|
|
+ if (unlikely(bond->dev->priv_flags & IFF_IN_NETPOLL)) {
|
|
|
+ struct netpoll *np = bond->dev->npinfo->netpoll;
|
|
|
+ slave_dev->npinfo = bond->dev->npinfo;
|
|
|
+ np->real_dev = np->dev = skb->dev;
|
|
|
+ slave_dev->priv_flags |= IFF_IN_NETPOLL;
|
|
|
+ netpoll_send_skb(np, skb);
|
|
|
+ slave_dev->priv_flags &= ~IFF_IN_NETPOLL;
|
|
|
+ np->dev = bond->dev;
|
|
|
+ } else
|
|
|
+#endif
|
|
|
+ dev_queue_xmit(skb);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -1256,6 +1268,61 @@ static void bond_detach_slave(struct bonding *bond, struct slave *slave)
|
|
|
bond->slave_cnt--;
|
|
|
}
|
|
|
|
|
|
+#ifdef CONFIG_NET_POLL_CONTROLLER
|
|
|
+/*
|
|
|
+ * You must hold read lock on bond->lock before calling this.
|
|
|
+ */
|
|
|
+static bool slaves_support_netpoll(struct net_device *bond_dev)
|
|
|
+{
|
|
|
+ struct bonding *bond = netdev_priv(bond_dev);
|
|
|
+ struct slave *slave;
|
|
|
+ int i = 0;
|
|
|
+ bool ret = true;
|
|
|
+
|
|
|
+ bond_for_each_slave(bond, slave, i) {
|
|
|
+ if ((slave->dev->priv_flags & IFF_DISABLE_NETPOLL) ||
|
|
|
+ !slave->dev->netdev_ops->ndo_poll_controller)
|
|
|
+ ret = false;
|
|
|
+ }
|
|
|
+ return i != 0 && ret;
|
|
|
+}
|
|
|
+
|
|
|
+static void bond_poll_controller(struct net_device *bond_dev)
|
|
|
+{
|
|
|
+ struct net_device *dev = bond_dev->npinfo->netpoll->real_dev;
|
|
|
+ if (dev != bond_dev)
|
|
|
+ netpoll_poll_dev(dev);
|
|
|
+}
|
|
|
+
|
|
|
+static void bond_netpoll_cleanup(struct net_device *bond_dev)
|
|
|
+{
|
|
|
+ struct bonding *bond = netdev_priv(bond_dev);
|
|
|
+ struct slave *slave;
|
|
|
+ const struct net_device_ops *ops;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ read_lock(&bond->lock);
|
|
|
+ bond_dev->npinfo = NULL;
|
|
|
+ bond_for_each_slave(bond, slave, i) {
|
|
|
+ if (slave->dev) {
|
|
|
+ ops = slave->dev->netdev_ops;
|
|
|
+ if (ops->ndo_netpoll_cleanup)
|
|
|
+ ops->ndo_netpoll_cleanup(slave->dev);
|
|
|
+ else
|
|
|
+ slave->dev->npinfo = NULL;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ read_unlock(&bond->lock);
|
|
|
+}
|
|
|
+
|
|
|
+#else
|
|
|
+
|
|
|
+static void bond_netpoll_cleanup(struct net_device *bond_dev)
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
/*---------------------------------- IOCTL ----------------------------------*/
|
|
|
|
|
|
static int bond_sethwaddr(struct net_device *bond_dev,
|
|
@@ -1674,6 +1741,18 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
|
|
|
|
|
|
bond_set_carrier(bond);
|
|
|
|
|
|
+#ifdef CONFIG_NET_POLL_CONTROLLER
|
|
|
+ if (slaves_support_netpoll(bond_dev)) {
|
|
|
+ bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL;
|
|
|
+ if (bond_dev->npinfo)
|
|
|
+ slave_dev->npinfo = bond_dev->npinfo;
|
|
|
+ } else if (!(bond_dev->priv_flags & IFF_DISABLE_NETPOLL)) {
|
|
|
+ bond_dev->priv_flags |= IFF_DISABLE_NETPOLL;
|
|
|
+ pr_info("New slave device %s does not support netpoll\n",
|
|
|
+ slave_dev->name);
|
|
|
+ pr_info("Disabling netpoll support for %s\n", bond_dev->name);
|
|
|
+ }
|
|
|
+#endif
|
|
|
read_unlock(&bond->lock);
|
|
|
|
|
|
res = bond_create_slave_symlinks(bond_dev, slave_dev);
|
|
@@ -1740,6 +1819,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
+ netdev_bonding_change(bond_dev, NETDEV_BONDING_DESLAVE);
|
|
|
write_lock_bh(&bond->lock);
|
|
|
|
|
|
slave = bond_get_slave_by_dev(bond, slave_dev);
|
|
@@ -1868,6 +1948,17 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
|
|
|
|
|
|
netdev_set_master(slave_dev, NULL);
|
|
|
|
|
|
+#ifdef CONFIG_NET_POLL_CONTROLLER
|
|
|
+ read_lock_bh(&bond->lock);
|
|
|
+ if (slaves_support_netpoll(bond_dev))
|
|
|
+ bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL;
|
|
|
+ read_unlock_bh(&bond->lock);
|
|
|
+ if (slave_dev->netdev_ops->ndo_netpoll_cleanup)
|
|
|
+ slave_dev->netdev_ops->ndo_netpoll_cleanup(slave_dev);
|
|
|
+ else
|
|
|
+ slave_dev->npinfo = NULL;
|
|
|
+#endif
|
|
|
+
|
|
|
/* close slave before restoring its mac address */
|
|
|
dev_close(slave_dev);
|
|
|
|
|
@@ -4406,6 +4497,10 @@ static const struct net_device_ops bond_netdev_ops = {
|
|
|
.ndo_vlan_rx_register = bond_vlan_rx_register,
|
|
|
.ndo_vlan_rx_add_vid = bond_vlan_rx_add_vid,
|
|
|
.ndo_vlan_rx_kill_vid = bond_vlan_rx_kill_vid,
|
|
|
+#ifdef CONFIG_NET_POLL_CONTROLLER
|
|
|
+ .ndo_netpoll_cleanup = bond_netpoll_cleanup,
|
|
|
+ .ndo_poll_controller = bond_poll_controller,
|
|
|
+#endif
|
|
|
};
|
|
|
|
|
|
static void bond_destructor(struct net_device *bond_dev)
|
|
@@ -4499,6 +4594,8 @@ static void bond_uninit(struct net_device *bond_dev)
|
|
|
{
|
|
|
struct bonding *bond = netdev_priv(bond_dev);
|
|
|
|
|
|
+ bond_netpoll_cleanup(bond_dev);
|
|
|
+
|
|
|
/* Release the bonded slaves */
|
|
|
bond_release_all(bond_dev);
|
|
|
|