summaryrefslogtreecommitdiff
path: root/drivers/net/bonding/bond_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/bonding/bond_main.c')
-rw-r--r--drivers/net/bonding/bond_main.c130
1 files changed, 114 insertions, 16 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 5e12462..a95a41b 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -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;
@@ -106,10 +107,13 @@ static int arp_interval = BOND_LINK_ARP_INTERV;
static char *arp_ip_target[BOND_MAX_ARP_TARGETS];
static char *arp_validate;
static char *fail_over_mac;
+static int all_slaves_active = 0;
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);
@@ -155,6 +159,10 @@ module_param(arp_validate, charp, 0);
MODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes: none (default), active, backup or all");
module_param(fail_over_mac, charp, 0);
MODULE_PARM_DESC(fail_over_mac, "For active-backup, do not set all slaves to the same MAC. none (default), active or follow");
+module_param(all_slaves_active, int, 0);
+MODULE_PARM_DESC(all_slaves_active, "Keep all frames received on an interface"
+ "by setting active flag for all slaves. "
+ "0 for never (default), 1 for always.");
/*----------------------------- Global variables ----------------------------*/
@@ -1522,16 +1530,32 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
}
}
+ /* If this is the first slave, then we need to set the master's hardware
+ * address to be the same as the slave's. */
+ if (bond->slave_cnt == 0)
+ memcpy(bond->dev->dev_addr, slave_dev->dev_addr,
+ slave_dev->addr_len);
+
+
new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL);
if (!new_slave) {
res = -ENOMEM;
goto err_undo_flags;
}
- /* save slave's original flags before calling
- * netdev_set_master and dev_open
+ /*
+ * Set the new_slave's queue_id to be zero. Queue ID mapping
+ * is set via sysfs or module option if desired.
*/
- new_slave->original_flags = slave_dev->flags;
+ 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);
+ if (res) {
+ pr_debug("Error %d calling dev_set_mtu\n", res);
+ goto err_free;
+ }
/*
* Save slave's original ("permanent") mac address for modes
@@ -1550,7 +1574,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
res = dev_set_mac_address(slave_dev, &addr);
if (res) {
pr_debug("Error %d calling set_mac_address\n", res);
- goto err_free;
+ goto err_restore_mtu;
}
}
@@ -1785,6 +1809,9 @@ err_restore_mac:
dev_set_mac_address(slave_dev, &addr);
}
+err_restore_mtu:
+ dev_set_mtu(slave_dev, new_slave->original_mtu);
+
err_free:
kfree(new_slave);
@@ -1969,6 +1996,8 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
dev_set_mac_address(slave_dev, &addr);
}
+ dev_set_mtu(slave_dev, slave->original_mtu);
+
slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB |
IFF_SLAVE_INACTIVE | IFF_BONDING |
IFF_SLAVE_NEEDARP);
@@ -2555,7 +2584,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
/*
* This target is not on a VLAN
*/
- if (rt->u.dst.dev == bond->dev) {
+ if (rt->dst.dev == bond->dev) {
ip_rt_put(rt);
pr_debug("basa: rtdev == bond->dev: arp_send\n");
bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
@@ -2566,7 +2595,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
vlan_id = 0;
list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id);
- if (vlan_dev == rt->u.dst.dev) {
+ if (vlan_dev == rt->dst.dev) {
vlan_id = vlan->vlan_id;
pr_debug("basa: vlan match on %s %d\n",
vlan_dev->name, vlan_id);
@@ -2584,7 +2613,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
if (net_ratelimit()) {
pr_warning("%s: no path to arp_ip_target %pI4 via rt.dev %s\n",
bond->dev->name, &fl.fl4_dst,
- rt->u.dst.dev ? rt->u.dst.dev->name : "NULL");
+ rt->dst.dev ? rt->dst.dev->name : "NULL");
}
ip_rt_put(rt);
}
@@ -3265,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)
@@ -3774,20 +3804,21 @@ static int bond_close(struct net_device *bond_dev)
return 0;
}
-static struct net_device_stats *bond_get_stats(struct net_device *bond_dev)
+static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
- struct net_device_stats *stats = &bond_dev->stats;
- struct net_device_stats local_stats;
+ struct rtnl_link_stats64 *stats = &bond_dev->stats64;
+ struct rtnl_link_stats64 local_stats;
struct slave *slave;
int i;
- memset(&local_stats, 0, sizeof(struct net_device_stats));
+ memset(&local_stats, 0, sizeof(local_stats));
read_lock_bh(&bond->lock);
bond_for_each_slave(bond, slave, i) {
- const struct net_device_stats *sstats = dev_get_stats(slave->dev);
+ const struct rtnl_link_stats64 *sstats =
+ dev_get_stats(slave->dev);
local_stats.rx_packets += sstats->rx_packets;
local_stats.rx_bytes += sstats->rx_bytes;
@@ -4401,9 +4432,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:
@@ -4488,7 +4569,8 @@ static const struct net_device_ops bond_netdev_ops = {
.ndo_open = bond_open,
.ndo_stop = bond_close,
.ndo_start_xmit = bond_start_xmit,
- .ndo_get_stats = bond_get_stats,
+ .ndo_select_queue = bond_select_queue,
+ .ndo_get_stats64 = bond_get_stats,
.ndo_do_ioctl = bond_do_ioctl,
.ndo_set_multicast_list = bond_set_multicast_list,
.ndo_change_mtu = bond_change_mtu,
@@ -4756,6 +4838,20 @@ 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 "
+ "0\n", all_slaves_active);
+ all_slaves_active = 0;
+ }
+
/* reset values for TLB/ALB */
if ((bond_mode == BOND_MODE_TLB) ||
(bond_mode == BOND_MODE_ALB)) {
@@ -4926,6 +5022,8 @@ 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) {
strncpy(params->primary, primary, IFNAMSIZ);
@@ -5012,8 +5110,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();