team: add multiqueue support
authorJiri Pirko <jiri@resnulli.us>
Fri, 20 Jul 2012 02:28:51 +0000 (02:28 +0000)
committerDavid S. Miller <davem@davemloft.net>
Fri, 20 Jul 2012 18:07:00 +0000 (11:07 -0700)
Largely copied from bonding code.

Signed-off-by: Jiri Pirko <jiri@resnulli.us>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/team/team.c
include/linux/if_team.h

index 813e1319095fb339800c5cd41b7f5e653cccbd13..b104c05225f7ea0964d3065b6789f945451d9c23 100644 (file)
@@ -27,6 +27,7 @@
 #include <net/rtnetlink.h>
 #include <net/genetlink.h>
 #include <net/netlink.h>
+#include <net/sch_generic.h>
 #include <linux/if_team.h>
 
 #define DRV_NAME "team"
@@ -1121,6 +1122,22 @@ static const struct team_option team_options[] = {
        },
 };
 
+static struct lock_class_key team_netdev_xmit_lock_key;
+static struct lock_class_key team_netdev_addr_lock_key;
+
+static void team_set_lockdep_class_one(struct net_device *dev,
+                                      struct netdev_queue *txq,
+                                      void *unused)
+{
+       lockdep_set_class(&txq->_xmit_lock, &team_netdev_xmit_lock_key);
+}
+
+static void team_set_lockdep_class(struct net_device *dev)
+{
+       lockdep_set_class(&dev->addr_list_lock, &team_netdev_addr_lock_key);
+       netdev_for_each_tx_queue(dev, team_set_lockdep_class_one, NULL);
+}
+
 static int team_init(struct net_device *dev)
 {
        struct team *team = netdev_priv(dev);
@@ -1148,6 +1165,8 @@ static int team_init(struct net_device *dev)
                goto err_options_register;
        netif_carrier_off(dev);
 
+       team_set_lockdep_class(dev);
+
        return 0;
 
 err_options_register:
@@ -1216,6 +1235,29 @@ static netdev_tx_t team_xmit(struct sk_buff *skb, struct net_device *dev)
        return NETDEV_TX_OK;
 }
 
+static u16 team_select_queue(struct net_device *dev, struct sk_buff *skb)
+{
+       /*
+        * This helper function exists to help dev_pick_tx get the correct
+        * destination queue.  Using a helper function skips a call to
+        * skb_tx_hash and will put the skbs in the queue we expect on their
+        * way down to the team driver.
+        */
+       u16 txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) : 0;
+
+       /*
+        * Save the original txq to restore before passing to the driver
+        */
+       qdisc_skb_cb(skb)->slave_dev_queue_mapping = skb->queue_mapping;
+
+       if (unlikely(txq >= dev->real_num_tx_queues)) {
+               do {
+                       txq -= dev->real_num_tx_queues;
+               } while (txq >= dev->real_num_tx_queues);
+       }
+       return txq;
+}
+
 static void team_change_rx_flags(struct net_device *dev, int change)
 {
        struct team *team = netdev_priv(dev);
@@ -1469,6 +1511,7 @@ static const struct net_device_ops team_netdev_ops = {
        .ndo_open               = team_open,
        .ndo_stop               = team_close,
        .ndo_start_xmit         = team_xmit,
+       .ndo_select_queue       = team_select_queue,
        .ndo_change_rx_flags    = team_change_rx_flags,
        .ndo_set_rx_mode        = team_set_rx_mode,
        .ndo_set_mac_address    = team_set_mac_address,
@@ -1543,12 +1586,24 @@ static int team_validate(struct nlattr *tb[], struct nlattr *data[])
        return 0;
 }
 
+static unsigned int team_get_num_tx_queues(void)
+{
+       return TEAM_DEFAULT_NUM_TX_QUEUES;
+}
+
+static unsigned int team_get_num_rx_queues(void)
+{
+       return TEAM_DEFAULT_NUM_RX_QUEUES;
+}
+
 static struct rtnl_link_ops team_link_ops __read_mostly = {
-       .kind           = DRV_NAME,
-       .priv_size      = sizeof(struct team),
-       .setup          = team_setup,
-       .newlink        = team_newlink,
-       .validate       = team_validate,
+       .kind                   = DRV_NAME,
+       .priv_size              = sizeof(struct team),
+       .setup                  = team_setup,
+       .newlink                = team_newlink,
+       .validate               = team_validate,
+       .get_num_tx_queues      = team_get_num_tx_queues,
+       .get_num_rx_queues      = team_get_num_rx_queues,
 };
 
 
index 7fd0cdeb9444a73577057b9c48ee87aca6b4055b..6960fc1841a7adc3bd42ff5b9a2221b78f2b9eb2 100644 (file)
@@ -14,6 +14,7 @@
 #ifdef __KERNEL__
 
 #include <linux/netpoll.h>
+#include <net/sch_generic.h>
 
 struct team_pcpu_stats {
        u64                     rx_packets;
@@ -98,6 +99,10 @@ static inline void team_netpoll_send_skb(struct team_port *port,
 static inline int team_dev_queue_xmit(struct team *team, struct team_port *port,
                                      struct sk_buff *skb)
 {
+       BUILD_BUG_ON(sizeof(skb->queue_mapping) !=
+                    sizeof(qdisc_skb_cb(skb)->slave_dev_queue_mapping));
+       skb_set_queue_mapping(skb, qdisc_skb_cb(skb)->slave_dev_queue_mapping);
+
        skb->dev = port->dev;
        if (unlikely(netpoll_tx_running(port->dev))) {
                team_netpoll_send_skb(port, skb);
@@ -236,6 +241,9 @@ extern void team_options_unregister(struct team *team,
 extern int team_mode_register(const struct team_mode *mode);
 extern void team_mode_unregister(const struct team_mode *mode);
 
+#define TEAM_DEFAULT_NUM_TX_QUEUES 16
+#define TEAM_DEFAULT_NUM_RX_QUEUES 16
+
 #endif /* __KERNEL__ */
 
 #define TEAM_STRING_MAX_LEN 32