|
@@ -90,6 +90,7 @@
|
|
|
#define BOND_LINK_ARP_INTERV 0
|
|
|
|
|
|
static int max_bonds = BOND_DEFAULT_MAX_BONDS;
|
|
|
+static int tx_queues = BOND_DEFAULT_TX_QUEUES;
|
|
|
static int num_grat_arp = 1;
|
|
|
static int num_unsol_na = 1;
|
|
|
static int miimon = BOND_LINK_MON_INTERV;
|
|
@@ -111,6 +112,8 @@ static struct bond_params bonding_defaults;
|
|
|
|
|
|
module_param(max_bonds, int, 0);
|
|
|
MODULE_PARM_DESC(max_bonds, "Max number of bonded devices");
|
|
|
+module_param(tx_queues, int, 0);
|
|
|
+MODULE_PARM_DESC(tx_queues, "Max number of transmit queues (default = 16)");
|
|
|
module_param(num_grat_arp, int, 0644);
|
|
|
MODULE_PARM_DESC(num_grat_arp, "Number of gratuitous ARP packets to send on failover event");
|
|
|
module_param(num_unsol_na, int, 0644);
|
|
@@ -1540,6 +1543,12 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
|
|
|
goto err_undo_flags;
|
|
|
}
|
|
|
|
|
|
+ /*
|
|
|
+ * Set the new_slave's queue_id to be zero. Queue ID mapping
|
|
|
+ * is set via sysfs or module option if desired.
|
|
|
+ */
|
|
|
+ new_slave->queue_id = 0;
|
|
|
+
|
|
|
/* Save slave's original mtu and then set it to match the bond */
|
|
|
new_slave->original_mtu = slave_dev->mtu;
|
|
|
res = dev_set_mtu(slave_dev, bond->dev->mtu);
|
|
@@ -3285,6 +3294,7 @@ static void bond_info_show_slave(struct seq_file *seq,
|
|
|
else
|
|
|
seq_puts(seq, "Aggregator ID: N/A\n");
|
|
|
}
|
|
|
+ seq_printf(seq, "Slave queue ID: %d\n", slave->queue_id);
|
|
|
}
|
|
|
|
|
|
static int bond_info_seq_show(struct seq_file *seq, void *v)
|
|
@@ -4421,9 +4431,59 @@ static void bond_set_xmit_hash_policy(struct bonding *bond)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Lookup the slave that corresponds to a qid
|
|
|
+ */
|
|
|
+static inline int bond_slave_override(struct bonding *bond,
|
|
|
+ struct sk_buff *skb)
|
|
|
+{
|
|
|
+ int i, res = 1;
|
|
|
+ struct slave *slave = NULL;
|
|
|
+ struct slave *check_slave;
|
|
|
+
|
|
|
+ read_lock(&bond->lock);
|
|
|
+
|
|
|
+ if (!BOND_IS_OK(bond) || !skb->queue_mapping)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ /* Find out if any slaves have the same mapping as this skb. */
|
|
|
+ bond_for_each_slave(bond, check_slave, i) {
|
|
|
+ if (check_slave->queue_id == skb->queue_mapping) {
|
|
|
+ slave = check_slave;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* If the slave isn't UP, use default transmit policy. */
|
|
|
+ if (slave && slave->queue_id && IS_UP(slave->dev) &&
|
|
|
+ (slave->link == BOND_LINK_UP)) {
|
|
|
+ res = bond_dev_queue_xmit(bond, skb, slave->dev);
|
|
|
+ }
|
|
|
+
|
|
|
+out:
|
|
|
+ read_unlock(&bond->lock);
|
|
|
+ return res;
|
|
|
+}
|
|
|
+
|
|
|
+static u16 bond_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 the a call to
|
|
|
+ * skb_tx_hash and will put the skbs in the queue we expect on their
|
|
|
+ * way down to the bonding driver.
|
|
|
+ */
|
|
|
+ return skb->queue_mapping;
|
|
|
+}
|
|
|
+
|
|
|
static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|
|
{
|
|
|
- const struct bonding *bond = netdev_priv(dev);
|
|
|
+ struct bonding *bond = netdev_priv(dev);
|
|
|
+
|
|
|
+ if (TX_QUEUE_OVERRIDE(bond->params.mode)) {
|
|
|
+ if (!bond_slave_override(bond, skb))
|
|
|
+ return NETDEV_TX_OK;
|
|
|
+ }
|
|
|
|
|
|
switch (bond->params.mode) {
|
|
|
case BOND_MODE_ROUNDROBIN:
|
|
@@ -4508,6 +4568,7 @@ static const struct net_device_ops bond_netdev_ops = {
|
|
|
.ndo_open = bond_open,
|
|
|
.ndo_stop = bond_close,
|
|
|
.ndo_start_xmit = bond_start_xmit,
|
|
|
+ .ndo_select_queue = bond_select_queue,
|
|
|
.ndo_get_stats = bond_get_stats,
|
|
|
.ndo_do_ioctl = bond_do_ioctl,
|
|
|
.ndo_set_multicast_list = bond_set_multicast_list,
|
|
@@ -4776,6 +4837,13 @@ static int bond_check_params(struct bond_params *params)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ if (tx_queues < 1 || tx_queues > 255) {
|
|
|
+ pr_warning("Warning: tx_queues (%d) should be between "
|
|
|
+ "1 and 255, resetting to %d\n",
|
|
|
+ tx_queues, BOND_DEFAULT_TX_QUEUES);
|
|
|
+ tx_queues = BOND_DEFAULT_TX_QUEUES;
|
|
|
+ }
|
|
|
+
|
|
|
if ((all_slaves_active != 0) && (all_slaves_active != 1)) {
|
|
|
pr_warning("Warning: all_slaves_active module parameter (%d), "
|
|
|
"not of valid value (0/1), so it was set to "
|
|
@@ -4953,6 +5021,7 @@ static int bond_check_params(struct bond_params *params)
|
|
|
params->primary[0] = 0;
|
|
|
params->primary_reselect = primary_reselect_value;
|
|
|
params->fail_over_mac = fail_over_mac_value;
|
|
|
+ params->tx_queues = tx_queues;
|
|
|
params->all_slaves_active = all_slaves_active;
|
|
|
|
|
|
if (primary) {
|
|
@@ -5040,8 +5109,8 @@ int bond_create(struct net *net, const char *name)
|
|
|
|
|
|
rtnl_lock();
|
|
|
|
|
|
- bond_dev = alloc_netdev(sizeof(struct bonding), name ? name : "",
|
|
|
- bond_setup);
|
|
|
+ bond_dev = alloc_netdev_mq(sizeof(struct bonding), name ? name : "",
|
|
|
+ bond_setup, tx_queues);
|
|
|
if (!bond_dev) {
|
|
|
pr_err("%s: eek! can't alloc netdev!\n", name);
|
|
|
rtnl_unlock();
|