diff options
author | WANG Cong <amwang@redhat.com> | 2010-05-06 03:48:51 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-05-06 03:48:51 -0400 |
commit | f6dc31a85cd46a959bdd987adad14c3b645e03c1 (patch) | |
tree | 5e60aa95287daa0262e90f0db36e280dea163578 | |
parent | c06ee961d3c0e51009cbd0e123b61fbb97f37d0b (diff) |
bonding: make bonding support netpoll
Based on Andy's work, but I modified a lot.
Similar to the patch for bridge, this patch does:
1) implement the 2 methods to support netpoll for bonding;
2) modify netpoll during forwarding packets via bonding;
3) disable netpoll support of bonding when a netpoll-unabled device
is added to bonding;
4) enable netpoll support when all underlying devices support netpoll.
Cc: Andy Gospodarek <gospo@redhat.com>
Cc: Jeff Moyer <jmoyer@redhat.com>
Cc: Matt Mackall <mpm@selenic.com>
Cc: Neil Horman <nhorman@tuxdriver.com>
Cc: Jay Vosburgh <fubar@us.ibm.com>
Cc: David Miller <davem@davemloft.net>
Signed-off-by: WANG Cong <amwang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/bonding/bond_main.c | 99 |
1 files changed, 98 insertions, 1 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 85e813c7762b..5e12462a9d5e 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c | |||
@@ -59,6 +59,7 @@ | |||
59 | #include <linux/uaccess.h> | 59 | #include <linux/uaccess.h> |
60 | #include <linux/errno.h> | 60 | #include <linux/errno.h> |
61 | #include <linux/netdevice.h> | 61 | #include <linux/netdevice.h> |
62 | #include <linux/netpoll.h> | ||
62 | #include <linux/inetdevice.h> | 63 | #include <linux/inetdevice.h> |
63 | #include <linux/igmp.h> | 64 | #include <linux/igmp.h> |
64 | #include <linux/etherdevice.h> | 65 | #include <linux/etherdevice.h> |
@@ -430,7 +431,18 @@ int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, | |||
430 | } | 431 | } |
431 | 432 | ||
432 | skb->priority = 1; | 433 | skb->priority = 1; |
433 | dev_queue_xmit(skb); | 434 | #ifdef CONFIG_NET_POLL_CONTROLLER |
435 | if (unlikely(bond->dev->priv_flags & IFF_IN_NETPOLL)) { | ||
436 | struct netpoll *np = bond->dev->npinfo->netpoll; | ||
437 | slave_dev->npinfo = bond->dev->npinfo; | ||
438 | np->real_dev = np->dev = skb->dev; | ||
439 | slave_dev->priv_flags |= IFF_IN_NETPOLL; | ||
440 | netpoll_send_skb(np, skb); | ||
441 | slave_dev->priv_flags &= ~IFF_IN_NETPOLL; | ||
442 | np->dev = bond->dev; | ||
443 | } else | ||
444 | #endif | ||
445 | dev_queue_xmit(skb); | ||
434 | 446 | ||
435 | return 0; | 447 | return 0; |
436 | } | 448 | } |
@@ -1256,6 +1268,61 @@ static void bond_detach_slave(struct bonding *bond, struct slave *slave) | |||
1256 | bond->slave_cnt--; | 1268 | bond->slave_cnt--; |
1257 | } | 1269 | } |
1258 | 1270 | ||
1271 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
1272 | /* | ||
1273 | * You must hold read lock on bond->lock before calling this. | ||
1274 | */ | ||
1275 | static bool slaves_support_netpoll(struct net_device *bond_dev) | ||
1276 | { | ||
1277 | struct bonding *bond = netdev_priv(bond_dev); | ||
1278 | struct slave *slave; | ||
1279 | int i = 0; | ||
1280 | bool ret = true; | ||
1281 | |||
1282 | bond_for_each_slave(bond, slave, i) { | ||
1283 | if ((slave->dev->priv_flags & IFF_DISABLE_NETPOLL) || | ||
1284 | !slave->dev->netdev_ops->ndo_poll_controller) | ||
1285 | ret = false; | ||
1286 | } | ||
1287 | return i != 0 && ret; | ||
1288 | } | ||
1289 | |||
1290 | static void bond_poll_controller(struct net_device *bond_dev) | ||
1291 | { | ||
1292 | struct net_device *dev = bond_dev->npinfo->netpoll->real_dev; | ||
1293 | if (dev != bond_dev) | ||
1294 | netpoll_poll_dev(dev); | ||
1295 | } | ||
1296 | |||
1297 | static void bond_netpoll_cleanup(struct net_device *bond_dev) | ||
1298 | { | ||
1299 | struct bonding *bond = netdev_priv(bond_dev); | ||
1300 | struct slave *slave; | ||
1301 | const struct net_device_ops *ops; | ||
1302 | int i; | ||
1303 | |||
1304 | read_lock(&bond->lock); | ||
1305 | bond_dev->npinfo = NULL; | ||
1306 | bond_for_each_slave(bond, slave, i) { | ||
1307 | if (slave->dev) { | ||
1308 | ops = slave->dev->netdev_ops; | ||
1309 | if (ops->ndo_netpoll_cleanup) | ||
1310 | ops->ndo_netpoll_cleanup(slave->dev); | ||
1311 | else | ||
1312 | slave->dev->npinfo = NULL; | ||
1313 | } | ||
1314 | } | ||
1315 | read_unlock(&bond->lock); | ||
1316 | } | ||
1317 | |||
1318 | #else | ||
1319 | |||
1320 | static void bond_netpoll_cleanup(struct net_device *bond_dev) | ||
1321 | { | ||
1322 | } | ||
1323 | |||
1324 | #endif | ||
1325 | |||
1259 | /*---------------------------------- IOCTL ----------------------------------*/ | 1326 | /*---------------------------------- IOCTL ----------------------------------*/ |
1260 | 1327 | ||
1261 | static int bond_sethwaddr(struct net_device *bond_dev, | 1328 | 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) | |||
1674 | 1741 | ||
1675 | bond_set_carrier(bond); | 1742 | bond_set_carrier(bond); |
1676 | 1743 | ||
1744 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
1745 | if (slaves_support_netpoll(bond_dev)) { | ||
1746 | bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL; | ||
1747 | if (bond_dev->npinfo) | ||
1748 | slave_dev->npinfo = bond_dev->npinfo; | ||
1749 | } else if (!(bond_dev->priv_flags & IFF_DISABLE_NETPOLL)) { | ||
1750 | bond_dev->priv_flags |= IFF_DISABLE_NETPOLL; | ||
1751 | pr_info("New slave device %s does not support netpoll\n", | ||
1752 | slave_dev->name); | ||
1753 | pr_info("Disabling netpoll support for %s\n", bond_dev->name); | ||
1754 | } | ||
1755 | #endif | ||
1677 | read_unlock(&bond->lock); | 1756 | read_unlock(&bond->lock); |
1678 | 1757 | ||
1679 | res = bond_create_slave_symlinks(bond_dev, slave_dev); | 1758 | 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) | |||
1740 | return -EINVAL; | 1819 | return -EINVAL; |
1741 | } | 1820 | } |
1742 | 1821 | ||
1822 | netdev_bonding_change(bond_dev, NETDEV_BONDING_DESLAVE); | ||
1743 | write_lock_bh(&bond->lock); | 1823 | write_lock_bh(&bond->lock); |
1744 | 1824 | ||
1745 | slave = bond_get_slave_by_dev(bond, slave_dev); | 1825 | 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) | |||
1868 | 1948 | ||
1869 | netdev_set_master(slave_dev, NULL); | 1949 | netdev_set_master(slave_dev, NULL); |
1870 | 1950 | ||
1951 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
1952 | read_lock_bh(&bond->lock); | ||
1953 | if (slaves_support_netpoll(bond_dev)) | ||
1954 | bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL; | ||
1955 | read_unlock_bh(&bond->lock); | ||
1956 | if (slave_dev->netdev_ops->ndo_netpoll_cleanup) | ||
1957 | slave_dev->netdev_ops->ndo_netpoll_cleanup(slave_dev); | ||
1958 | else | ||
1959 | slave_dev->npinfo = NULL; | ||
1960 | #endif | ||
1961 | |||
1871 | /* close slave before restoring its mac address */ | 1962 | /* close slave before restoring its mac address */ |
1872 | dev_close(slave_dev); | 1963 | dev_close(slave_dev); |
1873 | 1964 | ||
@@ -4406,6 +4497,10 @@ static const struct net_device_ops bond_netdev_ops = { | |||
4406 | .ndo_vlan_rx_register = bond_vlan_rx_register, | 4497 | .ndo_vlan_rx_register = bond_vlan_rx_register, |
4407 | .ndo_vlan_rx_add_vid = bond_vlan_rx_add_vid, | 4498 | .ndo_vlan_rx_add_vid = bond_vlan_rx_add_vid, |
4408 | .ndo_vlan_rx_kill_vid = bond_vlan_rx_kill_vid, | 4499 | .ndo_vlan_rx_kill_vid = bond_vlan_rx_kill_vid, |
4500 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
4501 | .ndo_netpoll_cleanup = bond_netpoll_cleanup, | ||
4502 | .ndo_poll_controller = bond_poll_controller, | ||
4503 | #endif | ||
4409 | }; | 4504 | }; |
4410 | 4505 | ||
4411 | static void bond_destructor(struct net_device *bond_dev) | 4506 | static void bond_destructor(struct net_device *bond_dev) |
@@ -4499,6 +4594,8 @@ static void bond_uninit(struct net_device *bond_dev) | |||
4499 | { | 4594 | { |
4500 | struct bonding *bond = netdev_priv(bond_dev); | 4595 | struct bonding *bond = netdev_priv(bond_dev); |
4501 | 4596 | ||
4597 | bond_netpoll_cleanup(bond_dev); | ||
4598 | |||
4502 | /* Release the bonded slaves */ | 4599 | /* Release the bonded slaves */ |
4503 | bond_release_all(bond_dev); | 4600 | bond_release_all(bond_dev); |
4504 | 4601 | ||