diff options
author | Jiri Pirko <jiri@resnulli.us> | 2012-07-19 22:28:51 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-07-20 14:07:00 -0400 |
commit | 6c85f2bdda2086d804e198a3f31b685bc2f86b04 (patch) | |
tree | 49abe1f74a0a3290cf611878a704914a9f5e6577 | |
parent | 8a540ff9e1d685b5feb0a9df5d2b74db1e0b4d39 (diff) |
team: add multiqueue support
Largely copied from bonding code.
Signed-off-by: Jiri Pirko <jiri@resnulli.us>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/team/team.c | 65 | ||||
-rw-r--r-- | include/linux/if_team.h | 8 |
2 files changed, 68 insertions, 5 deletions
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 813e1319095f..b104c05225f7 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <net/rtnetlink.h> | 27 | #include <net/rtnetlink.h> |
28 | #include <net/genetlink.h> | 28 | #include <net/genetlink.h> |
29 | #include <net/netlink.h> | 29 | #include <net/netlink.h> |
30 | #include <net/sch_generic.h> | ||
30 | #include <linux/if_team.h> | 31 | #include <linux/if_team.h> |
31 | 32 | ||
32 | #define DRV_NAME "team" | 33 | #define DRV_NAME "team" |
@@ -1121,6 +1122,22 @@ static const struct team_option team_options[] = { | |||
1121 | }, | 1122 | }, |
1122 | }; | 1123 | }; |
1123 | 1124 | ||
1125 | static struct lock_class_key team_netdev_xmit_lock_key; | ||
1126 | static struct lock_class_key team_netdev_addr_lock_key; | ||
1127 | |||
1128 | static void team_set_lockdep_class_one(struct net_device *dev, | ||
1129 | struct netdev_queue *txq, | ||
1130 | void *unused) | ||
1131 | { | ||
1132 | lockdep_set_class(&txq->_xmit_lock, &team_netdev_xmit_lock_key); | ||
1133 | } | ||
1134 | |||
1135 | static void team_set_lockdep_class(struct net_device *dev) | ||
1136 | { | ||
1137 | lockdep_set_class(&dev->addr_list_lock, &team_netdev_addr_lock_key); | ||
1138 | netdev_for_each_tx_queue(dev, team_set_lockdep_class_one, NULL); | ||
1139 | } | ||
1140 | |||
1124 | static int team_init(struct net_device *dev) | 1141 | static int team_init(struct net_device *dev) |
1125 | { | 1142 | { |
1126 | struct team *team = netdev_priv(dev); | 1143 | struct team *team = netdev_priv(dev); |
@@ -1148,6 +1165,8 @@ static int team_init(struct net_device *dev) | |||
1148 | goto err_options_register; | 1165 | goto err_options_register; |
1149 | netif_carrier_off(dev); | 1166 | netif_carrier_off(dev); |
1150 | 1167 | ||
1168 | team_set_lockdep_class(dev); | ||
1169 | |||
1151 | return 0; | 1170 | return 0; |
1152 | 1171 | ||
1153 | err_options_register: | 1172 | err_options_register: |
@@ -1216,6 +1235,29 @@ static netdev_tx_t team_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1216 | return NETDEV_TX_OK; | 1235 | return NETDEV_TX_OK; |
1217 | } | 1236 | } |
1218 | 1237 | ||
1238 | static u16 team_select_queue(struct net_device *dev, struct sk_buff *skb) | ||
1239 | { | ||
1240 | /* | ||
1241 | * This helper function exists to help dev_pick_tx get the correct | ||
1242 | * destination queue. Using a helper function skips a call to | ||
1243 | * skb_tx_hash and will put the skbs in the queue we expect on their | ||
1244 | * way down to the team driver. | ||
1245 | */ | ||
1246 | u16 txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) : 0; | ||
1247 | |||
1248 | /* | ||
1249 | * Save the original txq to restore before passing to the driver | ||
1250 | */ | ||
1251 | qdisc_skb_cb(skb)->slave_dev_queue_mapping = skb->queue_mapping; | ||
1252 | |||
1253 | if (unlikely(txq >= dev->real_num_tx_queues)) { | ||
1254 | do { | ||
1255 | txq -= dev->real_num_tx_queues; | ||
1256 | } while (txq >= dev->real_num_tx_queues); | ||
1257 | } | ||
1258 | return txq; | ||
1259 | } | ||
1260 | |||
1219 | static void team_change_rx_flags(struct net_device *dev, int change) | 1261 | static void team_change_rx_flags(struct net_device *dev, int change) |
1220 | { | 1262 | { |
1221 | struct team *team = netdev_priv(dev); | 1263 | struct team *team = netdev_priv(dev); |
@@ -1469,6 +1511,7 @@ static const struct net_device_ops team_netdev_ops = { | |||
1469 | .ndo_open = team_open, | 1511 | .ndo_open = team_open, |
1470 | .ndo_stop = team_close, | 1512 | .ndo_stop = team_close, |
1471 | .ndo_start_xmit = team_xmit, | 1513 | .ndo_start_xmit = team_xmit, |
1514 | .ndo_select_queue = team_select_queue, | ||
1472 | .ndo_change_rx_flags = team_change_rx_flags, | 1515 | .ndo_change_rx_flags = team_change_rx_flags, |
1473 | .ndo_set_rx_mode = team_set_rx_mode, | 1516 | .ndo_set_rx_mode = team_set_rx_mode, |
1474 | .ndo_set_mac_address = team_set_mac_address, | 1517 | .ndo_set_mac_address = team_set_mac_address, |
@@ -1543,12 +1586,24 @@ static int team_validate(struct nlattr *tb[], struct nlattr *data[]) | |||
1543 | return 0; | 1586 | return 0; |
1544 | } | 1587 | } |
1545 | 1588 | ||
1589 | static unsigned int team_get_num_tx_queues(void) | ||
1590 | { | ||
1591 | return TEAM_DEFAULT_NUM_TX_QUEUES; | ||
1592 | } | ||
1593 | |||
1594 | static unsigned int team_get_num_rx_queues(void) | ||
1595 | { | ||
1596 | return TEAM_DEFAULT_NUM_RX_QUEUES; | ||
1597 | } | ||
1598 | |||
1546 | static struct rtnl_link_ops team_link_ops __read_mostly = { | 1599 | static struct rtnl_link_ops team_link_ops __read_mostly = { |
1547 | .kind = DRV_NAME, | 1600 | .kind = DRV_NAME, |
1548 | .priv_size = sizeof(struct team), | 1601 | .priv_size = sizeof(struct team), |
1549 | .setup = team_setup, | 1602 | .setup = team_setup, |
1550 | .newlink = team_newlink, | 1603 | .newlink = team_newlink, |
1551 | .validate = team_validate, | 1604 | .validate = team_validate, |
1605 | .get_num_tx_queues = team_get_num_tx_queues, | ||
1606 | .get_num_rx_queues = team_get_num_rx_queues, | ||
1552 | }; | 1607 | }; |
1553 | 1608 | ||
1554 | 1609 | ||
diff --git a/include/linux/if_team.h b/include/linux/if_team.h index 7fd0cdeb9444..6960fc1841a7 100644 --- a/include/linux/if_team.h +++ b/include/linux/if_team.h | |||
@@ -14,6 +14,7 @@ | |||
14 | #ifdef __KERNEL__ | 14 | #ifdef __KERNEL__ |
15 | 15 | ||
16 | #include <linux/netpoll.h> | 16 | #include <linux/netpoll.h> |
17 | #include <net/sch_generic.h> | ||
17 | 18 | ||
18 | struct team_pcpu_stats { | 19 | struct team_pcpu_stats { |
19 | u64 rx_packets; | 20 | u64 rx_packets; |
@@ -98,6 +99,10 @@ static inline void team_netpoll_send_skb(struct team_port *port, | |||
98 | static inline int team_dev_queue_xmit(struct team *team, struct team_port *port, | 99 | static inline int team_dev_queue_xmit(struct team *team, struct team_port *port, |
99 | struct sk_buff *skb) | 100 | struct sk_buff *skb) |
100 | { | 101 | { |
102 | BUILD_BUG_ON(sizeof(skb->queue_mapping) != | ||
103 | sizeof(qdisc_skb_cb(skb)->slave_dev_queue_mapping)); | ||
104 | skb_set_queue_mapping(skb, qdisc_skb_cb(skb)->slave_dev_queue_mapping); | ||
105 | |||
101 | skb->dev = port->dev; | 106 | skb->dev = port->dev; |
102 | if (unlikely(netpoll_tx_running(port->dev))) { | 107 | if (unlikely(netpoll_tx_running(port->dev))) { |
103 | team_netpoll_send_skb(port, skb); | 108 | team_netpoll_send_skb(port, skb); |
@@ -236,6 +241,9 @@ extern void team_options_unregister(struct team *team, | |||
236 | extern int team_mode_register(const struct team_mode *mode); | 241 | extern int team_mode_register(const struct team_mode *mode); |
237 | extern void team_mode_unregister(const struct team_mode *mode); | 242 | extern void team_mode_unregister(const struct team_mode *mode); |
238 | 243 | ||
244 | #define TEAM_DEFAULT_NUM_TX_QUEUES 16 | ||
245 | #define TEAM_DEFAULT_NUM_RX_QUEUES 16 | ||
246 | |||
239 | #endif /* __KERNEL__ */ | 247 | #endif /* __KERNEL__ */ |
240 | 248 | ||
241 | #define TEAM_STRING_MAX_LEN 32 | 249 | #define TEAM_STRING_MAX_LEN 32 |