diff options
Diffstat (limited to 'drivers/net/bonding')
-rw-r--r-- | drivers/net/bonding/bond_alb.c | 33 | ||||
-rw-r--r-- | drivers/net/bonding/bond_main.c | 130 | ||||
-rw-r--r-- | drivers/net/bonding/bond_sysfs.c | 279 | ||||
-rw-r--r-- | drivers/net/bonding/bonding.h | 14 |
4 files changed, 330 insertions, 126 deletions
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 40fdc41446cc..25c14c6236f5 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c | |||
@@ -233,34 +233,27 @@ static void tlb_deinitialize(struct bonding *bond) | |||
233 | _unlock_tx_hashtbl(bond); | 233 | _unlock_tx_hashtbl(bond); |
234 | } | 234 | } |
235 | 235 | ||
236 | static long long compute_gap(struct slave *slave) | ||
237 | { | ||
238 | return (s64) (slave->speed << 20) - /* Convert to Megabit per sec */ | ||
239 | (s64) (SLAVE_TLB_INFO(slave).load << 3); /* Bytes to bits */ | ||
240 | } | ||
241 | |||
236 | /* Caller must hold bond lock for read */ | 242 | /* Caller must hold bond lock for read */ |
237 | static struct slave *tlb_get_least_loaded_slave(struct bonding *bond) | 243 | static struct slave *tlb_get_least_loaded_slave(struct bonding *bond) |
238 | { | 244 | { |
239 | struct slave *slave, *least_loaded; | 245 | struct slave *slave, *least_loaded; |
240 | s64 max_gap; | 246 | long long max_gap; |
241 | int i, found = 0; | 247 | int i; |
242 | |||
243 | /* Find the first enabled slave */ | ||
244 | bond_for_each_slave(bond, slave, i) { | ||
245 | if (SLAVE_IS_OK(slave)) { | ||
246 | found = 1; | ||
247 | break; | ||
248 | } | ||
249 | } | ||
250 | |||
251 | if (!found) { | ||
252 | return NULL; | ||
253 | } | ||
254 | 248 | ||
255 | least_loaded = slave; | 249 | least_loaded = NULL; |
256 | max_gap = (s64)(slave->speed << 20) - /* Convert to Megabit per sec */ | 250 | max_gap = LLONG_MIN; |
257 | (s64)(SLAVE_TLB_INFO(slave).load << 3); /* Bytes to bits */ | ||
258 | 251 | ||
259 | /* Find the slave with the largest gap */ | 252 | /* Find the slave with the largest gap */ |
260 | bond_for_each_slave_from(bond, slave, i, least_loaded) { | 253 | bond_for_each_slave(bond, slave, i) { |
261 | if (SLAVE_IS_OK(slave)) { | 254 | if (SLAVE_IS_OK(slave)) { |
262 | s64 gap = (s64)(slave->speed << 20) - | 255 | long long gap = compute_gap(slave); |
263 | (s64)(SLAVE_TLB_INFO(slave).load << 3); | 256 | |
264 | if (max_gap < gap) { | 257 | if (max_gap < gap) { |
265 | least_loaded = slave; | 258 | least_loaded = slave; |
266 | max_gap = gap; | 259 | max_gap = gap; |
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 5e12462a9d5e..a95a41b74b4e 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c | |||
@@ -90,6 +90,7 @@ | |||
90 | #define BOND_LINK_ARP_INTERV 0 | 90 | #define BOND_LINK_ARP_INTERV 0 |
91 | 91 | ||
92 | static int max_bonds = BOND_DEFAULT_MAX_BONDS; | 92 | static int max_bonds = BOND_DEFAULT_MAX_BONDS; |
93 | static int tx_queues = BOND_DEFAULT_TX_QUEUES; | ||
93 | static int num_grat_arp = 1; | 94 | static int num_grat_arp = 1; |
94 | static int num_unsol_na = 1; | 95 | static int num_unsol_na = 1; |
95 | static int miimon = BOND_LINK_MON_INTERV; | 96 | static int miimon = BOND_LINK_MON_INTERV; |
@@ -106,10 +107,13 @@ static int arp_interval = BOND_LINK_ARP_INTERV; | |||
106 | static char *arp_ip_target[BOND_MAX_ARP_TARGETS]; | 107 | static char *arp_ip_target[BOND_MAX_ARP_TARGETS]; |
107 | static char *arp_validate; | 108 | static char *arp_validate; |
108 | static char *fail_over_mac; | 109 | static char *fail_over_mac; |
110 | static int all_slaves_active = 0; | ||
109 | static struct bond_params bonding_defaults; | 111 | static struct bond_params bonding_defaults; |
110 | 112 | ||
111 | module_param(max_bonds, int, 0); | 113 | module_param(max_bonds, int, 0); |
112 | MODULE_PARM_DESC(max_bonds, "Max number of bonded devices"); | 114 | MODULE_PARM_DESC(max_bonds, "Max number of bonded devices"); |
115 | module_param(tx_queues, int, 0); | ||
116 | MODULE_PARM_DESC(tx_queues, "Max number of transmit queues (default = 16)"); | ||
113 | module_param(num_grat_arp, int, 0644); | 117 | module_param(num_grat_arp, int, 0644); |
114 | MODULE_PARM_DESC(num_grat_arp, "Number of gratuitous ARP packets to send on failover event"); | 118 | MODULE_PARM_DESC(num_grat_arp, "Number of gratuitous ARP packets to send on failover event"); |
115 | module_param(num_unsol_na, int, 0644); | 119 | module_param(num_unsol_na, int, 0644); |
@@ -155,6 +159,10 @@ module_param(arp_validate, charp, 0); | |||
155 | MODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes: none (default), active, backup or all"); | 159 | MODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes: none (default), active, backup or all"); |
156 | module_param(fail_over_mac, charp, 0); | 160 | module_param(fail_over_mac, charp, 0); |
157 | MODULE_PARM_DESC(fail_over_mac, "For active-backup, do not set all slaves to the same MAC. none (default), active or follow"); | 161 | MODULE_PARM_DESC(fail_over_mac, "For active-backup, do not set all slaves to the same MAC. none (default), active or follow"); |
162 | module_param(all_slaves_active, int, 0); | ||
163 | MODULE_PARM_DESC(all_slaves_active, "Keep all frames received on an interface" | ||
164 | "by setting active flag for all slaves. " | ||
165 | "0 for never (default), 1 for always."); | ||
158 | 166 | ||
159 | /*----------------------------- Global variables ----------------------------*/ | 167 | /*----------------------------- Global variables ----------------------------*/ |
160 | 168 | ||
@@ -1522,16 +1530,32 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) | |||
1522 | } | 1530 | } |
1523 | } | 1531 | } |
1524 | 1532 | ||
1533 | /* If this is the first slave, then we need to set the master's hardware | ||
1534 | * address to be the same as the slave's. */ | ||
1535 | if (bond->slave_cnt == 0) | ||
1536 | memcpy(bond->dev->dev_addr, slave_dev->dev_addr, | ||
1537 | slave_dev->addr_len); | ||
1538 | |||
1539 | |||
1525 | new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL); | 1540 | new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL); |
1526 | if (!new_slave) { | 1541 | if (!new_slave) { |
1527 | res = -ENOMEM; | 1542 | res = -ENOMEM; |
1528 | goto err_undo_flags; | 1543 | goto err_undo_flags; |
1529 | } | 1544 | } |
1530 | 1545 | ||
1531 | /* save slave's original flags before calling | 1546 | /* |
1532 | * netdev_set_master and dev_open | 1547 | * Set the new_slave's queue_id to be zero. Queue ID mapping |
1548 | * is set via sysfs or module option if desired. | ||
1533 | */ | 1549 | */ |
1534 | new_slave->original_flags = slave_dev->flags; | 1550 | new_slave->queue_id = 0; |
1551 | |||
1552 | /* Save slave's original mtu and then set it to match the bond */ | ||
1553 | new_slave->original_mtu = slave_dev->mtu; | ||
1554 | res = dev_set_mtu(slave_dev, bond->dev->mtu); | ||
1555 | if (res) { | ||
1556 | pr_debug("Error %d calling dev_set_mtu\n", res); | ||
1557 | goto err_free; | ||
1558 | } | ||
1535 | 1559 | ||
1536 | /* | 1560 | /* |
1537 | * Save slave's original ("permanent") mac address for modes | 1561 | * 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) | |||
1550 | res = dev_set_mac_address(slave_dev, &addr); | 1574 | res = dev_set_mac_address(slave_dev, &addr); |
1551 | if (res) { | 1575 | if (res) { |
1552 | pr_debug("Error %d calling set_mac_address\n", res); | 1576 | pr_debug("Error %d calling set_mac_address\n", res); |
1553 | goto err_free; | 1577 | goto err_restore_mtu; |
1554 | } | 1578 | } |
1555 | } | 1579 | } |
1556 | 1580 | ||
@@ -1785,6 +1809,9 @@ err_restore_mac: | |||
1785 | dev_set_mac_address(slave_dev, &addr); | 1809 | dev_set_mac_address(slave_dev, &addr); |
1786 | } | 1810 | } |
1787 | 1811 | ||
1812 | err_restore_mtu: | ||
1813 | dev_set_mtu(slave_dev, new_slave->original_mtu); | ||
1814 | |||
1788 | err_free: | 1815 | err_free: |
1789 | kfree(new_slave); | 1816 | kfree(new_slave); |
1790 | 1817 | ||
@@ -1969,6 +1996,8 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) | |||
1969 | dev_set_mac_address(slave_dev, &addr); | 1996 | dev_set_mac_address(slave_dev, &addr); |
1970 | } | 1997 | } |
1971 | 1998 | ||
1999 | dev_set_mtu(slave_dev, slave->original_mtu); | ||
2000 | |||
1972 | slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB | | 2001 | slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB | |
1973 | IFF_SLAVE_INACTIVE | IFF_BONDING | | 2002 | IFF_SLAVE_INACTIVE | IFF_BONDING | |
1974 | IFF_SLAVE_NEEDARP); | 2003 | IFF_SLAVE_NEEDARP); |
@@ -2555,7 +2584,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) | |||
2555 | /* | 2584 | /* |
2556 | * This target is not on a VLAN | 2585 | * This target is not on a VLAN |
2557 | */ | 2586 | */ |
2558 | if (rt->u.dst.dev == bond->dev) { | 2587 | if (rt->dst.dev == bond->dev) { |
2559 | ip_rt_put(rt); | 2588 | ip_rt_put(rt); |
2560 | pr_debug("basa: rtdev == bond->dev: arp_send\n"); | 2589 | pr_debug("basa: rtdev == bond->dev: arp_send\n"); |
2561 | bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], | 2590 | 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) | |||
2566 | vlan_id = 0; | 2595 | vlan_id = 0; |
2567 | list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { | 2596 | list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { |
2568 | vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id); | 2597 | vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id); |
2569 | if (vlan_dev == rt->u.dst.dev) { | 2598 | if (vlan_dev == rt->dst.dev) { |
2570 | vlan_id = vlan->vlan_id; | 2599 | vlan_id = vlan->vlan_id; |
2571 | pr_debug("basa: vlan match on %s %d\n", | 2600 | pr_debug("basa: vlan match on %s %d\n", |
2572 | vlan_dev->name, vlan_id); | 2601 | vlan_dev->name, vlan_id); |
@@ -2584,7 +2613,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) | |||
2584 | if (net_ratelimit()) { | 2613 | if (net_ratelimit()) { |
2585 | pr_warning("%s: no path to arp_ip_target %pI4 via rt.dev %s\n", | 2614 | pr_warning("%s: no path to arp_ip_target %pI4 via rt.dev %s\n", |
2586 | bond->dev->name, &fl.fl4_dst, | 2615 | bond->dev->name, &fl.fl4_dst, |
2587 | rt->u.dst.dev ? rt->u.dst.dev->name : "NULL"); | 2616 | rt->dst.dev ? rt->dst.dev->name : "NULL"); |
2588 | } | 2617 | } |
2589 | ip_rt_put(rt); | 2618 | ip_rt_put(rt); |
2590 | } | 2619 | } |
@@ -3265,6 +3294,7 @@ static void bond_info_show_slave(struct seq_file *seq, | |||
3265 | else | 3294 | else |
3266 | seq_puts(seq, "Aggregator ID: N/A\n"); | 3295 | seq_puts(seq, "Aggregator ID: N/A\n"); |
3267 | } | 3296 | } |
3297 | seq_printf(seq, "Slave queue ID: %d\n", slave->queue_id); | ||
3268 | } | 3298 | } |
3269 | 3299 | ||
3270 | static int bond_info_seq_show(struct seq_file *seq, void *v) | 3300 | 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) | |||
3774 | return 0; | 3804 | return 0; |
3775 | } | 3805 | } |
3776 | 3806 | ||
3777 | static struct net_device_stats *bond_get_stats(struct net_device *bond_dev) | 3807 | static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev) |
3778 | { | 3808 | { |
3779 | struct bonding *bond = netdev_priv(bond_dev); | 3809 | struct bonding *bond = netdev_priv(bond_dev); |
3780 | struct net_device_stats *stats = &bond_dev->stats; | 3810 | struct rtnl_link_stats64 *stats = &bond_dev->stats64; |
3781 | struct net_device_stats local_stats; | 3811 | struct rtnl_link_stats64 local_stats; |
3782 | struct slave *slave; | 3812 | struct slave *slave; |
3783 | int i; | 3813 | int i; |
3784 | 3814 | ||
3785 | memset(&local_stats, 0, sizeof(struct net_device_stats)); | 3815 | memset(&local_stats, 0, sizeof(local_stats)); |
3786 | 3816 | ||
3787 | read_lock_bh(&bond->lock); | 3817 | read_lock_bh(&bond->lock); |
3788 | 3818 | ||
3789 | bond_for_each_slave(bond, slave, i) { | 3819 | bond_for_each_slave(bond, slave, i) { |
3790 | const struct net_device_stats *sstats = dev_get_stats(slave->dev); | 3820 | const struct rtnl_link_stats64 *sstats = |
3821 | dev_get_stats(slave->dev); | ||
3791 | 3822 | ||
3792 | local_stats.rx_packets += sstats->rx_packets; | 3823 | local_stats.rx_packets += sstats->rx_packets; |
3793 | local_stats.rx_bytes += sstats->rx_bytes; | 3824 | local_stats.rx_bytes += sstats->rx_bytes; |
@@ -4401,9 +4432,59 @@ static void bond_set_xmit_hash_policy(struct bonding *bond) | |||
4401 | } | 4432 | } |
4402 | } | 4433 | } |
4403 | 4434 | ||
4435 | /* | ||
4436 | * Lookup the slave that corresponds to a qid | ||
4437 | */ | ||
4438 | static inline int bond_slave_override(struct bonding *bond, | ||
4439 | struct sk_buff *skb) | ||
4440 | { | ||
4441 | int i, res = 1; | ||
4442 | struct slave *slave = NULL; | ||
4443 | struct slave *check_slave; | ||
4444 | |||
4445 | read_lock(&bond->lock); | ||
4446 | |||
4447 | if (!BOND_IS_OK(bond) || !skb->queue_mapping) | ||
4448 | goto out; | ||
4449 | |||
4450 | /* Find out if any slaves have the same mapping as this skb. */ | ||
4451 | bond_for_each_slave(bond, check_slave, i) { | ||
4452 | if (check_slave->queue_id == skb->queue_mapping) { | ||
4453 | slave = check_slave; | ||
4454 | break; | ||
4455 | } | ||
4456 | } | ||
4457 | |||
4458 | /* If the slave isn't UP, use default transmit policy. */ | ||
4459 | if (slave && slave->queue_id && IS_UP(slave->dev) && | ||
4460 | (slave->link == BOND_LINK_UP)) { | ||
4461 | res = bond_dev_queue_xmit(bond, skb, slave->dev); | ||
4462 | } | ||
4463 | |||
4464 | out: | ||
4465 | read_unlock(&bond->lock); | ||
4466 | return res; | ||
4467 | } | ||
4468 | |||
4469 | static u16 bond_select_queue(struct net_device *dev, struct sk_buff *skb) | ||
4470 | { | ||
4471 | /* | ||
4472 | * This helper function exists to help dev_pick_tx get the correct | ||
4473 | * destination queue. Using a helper function skips the a call to | ||
4474 | * skb_tx_hash and will put the skbs in the queue we expect on their | ||
4475 | * way down to the bonding driver. | ||
4476 | */ | ||
4477 | return skb->queue_mapping; | ||
4478 | } | ||
4479 | |||
4404 | static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev) | 4480 | static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev) |
4405 | { | 4481 | { |
4406 | const struct bonding *bond = netdev_priv(dev); | 4482 | struct bonding *bond = netdev_priv(dev); |
4483 | |||
4484 | if (TX_QUEUE_OVERRIDE(bond->params.mode)) { | ||
4485 | if (!bond_slave_override(bond, skb)) | ||
4486 | return NETDEV_TX_OK; | ||
4487 | } | ||
4407 | 4488 | ||
4408 | switch (bond->params.mode) { | 4489 | switch (bond->params.mode) { |
4409 | case BOND_MODE_ROUNDROBIN: | 4490 | case BOND_MODE_ROUNDROBIN: |
@@ -4488,7 +4569,8 @@ static const struct net_device_ops bond_netdev_ops = { | |||
4488 | .ndo_open = bond_open, | 4569 | .ndo_open = bond_open, |
4489 | .ndo_stop = bond_close, | 4570 | .ndo_stop = bond_close, |
4490 | .ndo_start_xmit = bond_start_xmit, | 4571 | .ndo_start_xmit = bond_start_xmit, |
4491 | .ndo_get_stats = bond_get_stats, | 4572 | .ndo_select_queue = bond_select_queue, |
4573 | .ndo_get_stats64 = bond_get_stats, | ||
4492 | .ndo_do_ioctl = bond_do_ioctl, | 4574 | .ndo_do_ioctl = bond_do_ioctl, |
4493 | .ndo_set_multicast_list = bond_set_multicast_list, | 4575 | .ndo_set_multicast_list = bond_set_multicast_list, |
4494 | .ndo_change_mtu = bond_change_mtu, | 4576 | .ndo_change_mtu = bond_change_mtu, |
@@ -4756,6 +4838,20 @@ static int bond_check_params(struct bond_params *params) | |||
4756 | } | 4838 | } |
4757 | } | 4839 | } |
4758 | 4840 | ||
4841 | if (tx_queues < 1 || tx_queues > 255) { | ||
4842 | pr_warning("Warning: tx_queues (%d) should be between " | ||
4843 | "1 and 255, resetting to %d\n", | ||
4844 | tx_queues, BOND_DEFAULT_TX_QUEUES); | ||
4845 | tx_queues = BOND_DEFAULT_TX_QUEUES; | ||
4846 | } | ||
4847 | |||
4848 | if ((all_slaves_active != 0) && (all_slaves_active != 1)) { | ||
4849 | pr_warning("Warning: all_slaves_active module parameter (%d), " | ||
4850 | "not of valid value (0/1), so it was set to " | ||
4851 | "0\n", all_slaves_active); | ||
4852 | all_slaves_active = 0; | ||
4853 | } | ||
4854 | |||
4759 | /* reset values for TLB/ALB */ | 4855 | /* reset values for TLB/ALB */ |
4760 | if ((bond_mode == BOND_MODE_TLB) || | 4856 | if ((bond_mode == BOND_MODE_TLB) || |
4761 | (bond_mode == BOND_MODE_ALB)) { | 4857 | (bond_mode == BOND_MODE_ALB)) { |
@@ -4926,6 +5022,8 @@ static int bond_check_params(struct bond_params *params) | |||
4926 | params->primary[0] = 0; | 5022 | params->primary[0] = 0; |
4927 | params->primary_reselect = primary_reselect_value; | 5023 | params->primary_reselect = primary_reselect_value; |
4928 | params->fail_over_mac = fail_over_mac_value; | 5024 | params->fail_over_mac = fail_over_mac_value; |
5025 | params->tx_queues = tx_queues; | ||
5026 | params->all_slaves_active = all_slaves_active; | ||
4929 | 5027 | ||
4930 | if (primary) { | 5028 | if (primary) { |
4931 | strncpy(params->primary, primary, IFNAMSIZ); | 5029 | strncpy(params->primary, primary, IFNAMSIZ); |
@@ -5012,8 +5110,8 @@ int bond_create(struct net *net, const char *name) | |||
5012 | 5110 | ||
5013 | rtnl_lock(); | 5111 | rtnl_lock(); |
5014 | 5112 | ||
5015 | bond_dev = alloc_netdev(sizeof(struct bonding), name ? name : "", | 5113 | bond_dev = alloc_netdev_mq(sizeof(struct bonding), name ? name : "", |
5016 | bond_setup); | 5114 | bond_setup, tx_queues); |
5017 | if (!bond_dev) { | 5115 | if (!bond_dev) { |
5018 | pr_err("%s: eek! can't alloc netdev!\n", name); | 5116 | pr_err("%s: eek! can't alloc netdev!\n", name); |
5019 | rtnl_unlock(); | 5117 | rtnl_unlock(); |
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index b8bec086daa1..f9a034361a8e 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c | |||
@@ -211,7 +211,8 @@ static ssize_t bonding_show_slaves(struct device *d, | |||
211 | /* | 211 | /* |
212 | * Set the slaves in the current bond. The bond interface must be | 212 | * Set the slaves in the current bond. The bond interface must be |
213 | * up for this to succeed. | 213 | * up for this to succeed. |
214 | * This function is largely the same flow as bonding_update_bonds(). | 214 | * This is supposed to be only thin wrapper for bond_enslave and bond_release. |
215 | * All hard work should be done there. | ||
215 | */ | 216 | */ |
216 | static ssize_t bonding_store_slaves(struct device *d, | 217 | static ssize_t bonding_store_slaves(struct device *d, |
217 | struct device_attribute *attr, | 218 | struct device_attribute *attr, |
@@ -219,10 +220,8 @@ static ssize_t bonding_store_slaves(struct device *d, | |||
219 | { | 220 | { |
220 | char command[IFNAMSIZ + 1] = { 0, }; | 221 | char command[IFNAMSIZ + 1] = { 0, }; |
221 | char *ifname; | 222 | char *ifname; |
222 | int i, res, found, ret = count; | 223 | int res, ret = count; |
223 | u32 original_mtu; | 224 | struct net_device *dev; |
224 | struct slave *slave; | ||
225 | struct net_device *dev = NULL; | ||
226 | struct bonding *bond = to_bond(d); | 225 | struct bonding *bond = to_bond(d); |
227 | 226 | ||
228 | /* Quick sanity check -- is the bond interface up? */ | 227 | /* Quick sanity check -- is the bond interface up? */ |
@@ -231,8 +230,6 @@ static ssize_t bonding_store_slaves(struct device *d, | |||
231 | bond->dev->name); | 230 | bond->dev->name); |
232 | } | 231 | } |
233 | 232 | ||
234 | /* Note: We can't hold bond->lock here, as bond_create grabs it. */ | ||
235 | |||
236 | if (!rtnl_trylock()) | 233 | if (!rtnl_trylock()) |
237 | return restart_syscall(); | 234 | return restart_syscall(); |
238 | 235 | ||
@@ -242,91 +239,33 @@ static ssize_t bonding_store_slaves(struct device *d, | |||
242 | !dev_valid_name(ifname)) | 239 | !dev_valid_name(ifname)) |
243 | goto err_no_cmd; | 240 | goto err_no_cmd; |
244 | 241 | ||
245 | if (command[0] == '+') { | 242 | dev = __dev_get_by_name(dev_net(bond->dev), ifname); |
246 | 243 | if (!dev) { | |
247 | /* Got a slave name in ifname. Is it already in the list? */ | 244 | pr_info("%s: Interface %s does not exist!\n", |
248 | found = 0; | 245 | bond->dev->name, ifname); |
249 | 246 | ret = -ENODEV; | |
250 | dev = __dev_get_by_name(dev_net(bond->dev), ifname); | 247 | goto out; |
251 | if (!dev) { | 248 | } |
252 | pr_info("%s: Interface %s does not exist!\n", | ||
253 | bond->dev->name, ifname); | ||
254 | ret = -ENODEV; | ||
255 | goto out; | ||
256 | } | ||
257 | |||
258 | if (dev->flags & IFF_UP) { | ||
259 | pr_err("%s: Error: Unable to enslave %s because it is already up.\n", | ||
260 | bond->dev->name, dev->name); | ||
261 | ret = -EPERM; | ||
262 | goto out; | ||
263 | } | ||
264 | |||
265 | read_lock(&bond->lock); | ||
266 | bond_for_each_slave(bond, slave, i) | ||
267 | if (slave->dev == dev) { | ||
268 | pr_err("%s: Interface %s is already enslaved!\n", | ||
269 | bond->dev->name, ifname); | ||
270 | ret = -EPERM; | ||
271 | read_unlock(&bond->lock); | ||
272 | goto out; | ||
273 | } | ||
274 | read_unlock(&bond->lock); | ||
275 | |||
276 | pr_info("%s: Adding slave %s.\n", bond->dev->name, ifname); | ||
277 | |||
278 | /* If this is the first slave, then we need to set | ||
279 | the master's hardware address to be the same as the | ||
280 | slave's. */ | ||
281 | if (is_zero_ether_addr(bond->dev->dev_addr)) | ||
282 | memcpy(bond->dev->dev_addr, dev->dev_addr, | ||
283 | dev->addr_len); | ||
284 | |||
285 | /* Set the slave's MTU to match the bond */ | ||
286 | original_mtu = dev->mtu; | ||
287 | res = dev_set_mtu(dev, bond->dev->mtu); | ||
288 | if (res) { | ||
289 | ret = res; | ||
290 | goto out; | ||
291 | } | ||
292 | 249 | ||
250 | switch (command[0]) { | ||
251 | case '+': | ||
252 | pr_info("%s: Adding slave %s.\n", bond->dev->name, dev->name); | ||
293 | res = bond_enslave(bond->dev, dev); | 253 | res = bond_enslave(bond->dev, dev); |
294 | bond_for_each_slave(bond, slave, i) | 254 | break; |
295 | if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0) | ||
296 | slave->original_mtu = original_mtu; | ||
297 | if (res) | ||
298 | ret = res; | ||
299 | 255 | ||
300 | goto out; | 256 | case '-': |
301 | } | 257 | pr_info("%s: Removing slave %s.\n", bond->dev->name, dev->name); |
258 | res = bond_release(bond->dev, dev); | ||
259 | break; | ||
302 | 260 | ||
303 | if (command[0] == '-') { | 261 | default: |
304 | dev = NULL; | 262 | goto err_no_cmd; |
305 | original_mtu = 0; | ||
306 | bond_for_each_slave(bond, slave, i) | ||
307 | if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0) { | ||
308 | dev = slave->dev; | ||
309 | original_mtu = slave->original_mtu; | ||
310 | break; | ||
311 | } | ||
312 | if (dev) { | ||
313 | pr_info("%s: Removing slave %s\n", | ||
314 | bond->dev->name, dev->name); | ||
315 | res = bond_release(bond->dev, dev); | ||
316 | if (res) { | ||
317 | ret = res; | ||
318 | goto out; | ||
319 | } | ||
320 | /* set the slave MTU to the default */ | ||
321 | dev_set_mtu(dev, original_mtu); | ||
322 | } else { | ||
323 | pr_err("unable to remove non-existent slave %s for bond %s.\n", | ||
324 | ifname, bond->dev->name); | ||
325 | ret = -ENODEV; | ||
326 | } | ||
327 | goto out; | ||
328 | } | 263 | } |
329 | 264 | ||
265 | if (res) | ||
266 | ret = res; | ||
267 | goto out; | ||
268 | |||
330 | err_no_cmd: | 269 | err_no_cmd: |
331 | pr_err("no command found in slaves file for bond %s. Use +ifname or -ifname.\n", | 270 | pr_err("no command found in slaves file for bond %s. Use +ifname or -ifname.\n", |
332 | bond->dev->name); | 271 | bond->dev->name); |
@@ -1472,7 +1411,173 @@ static ssize_t bonding_show_ad_partner_mac(struct device *d, | |||
1472 | } | 1411 | } |
1473 | static DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, NULL); | 1412 | static DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, NULL); |
1474 | 1413 | ||
1414 | /* | ||
1415 | * Show the queue_ids of the slaves in the current bond. | ||
1416 | */ | ||
1417 | static ssize_t bonding_show_queue_id(struct device *d, | ||
1418 | struct device_attribute *attr, | ||
1419 | char *buf) | ||
1420 | { | ||
1421 | struct slave *slave; | ||
1422 | int i, res = 0; | ||
1423 | struct bonding *bond = to_bond(d); | ||
1424 | |||
1425 | if (!rtnl_trylock()) | ||
1426 | return restart_syscall(); | ||
1475 | 1427 | ||
1428 | read_lock(&bond->lock); | ||
1429 | bond_for_each_slave(bond, slave, i) { | ||
1430 | if (res > (PAGE_SIZE - 6)) { | ||
1431 | /* not enough space for another interface name */ | ||
1432 | if ((PAGE_SIZE - res) > 10) | ||
1433 | res = PAGE_SIZE - 10; | ||
1434 | res += sprintf(buf + res, "++more++ "); | ||
1435 | break; | ||
1436 | } | ||
1437 | res += sprintf(buf + res, "%s:%d ", | ||
1438 | slave->dev->name, slave->queue_id); | ||
1439 | } | ||
1440 | read_unlock(&bond->lock); | ||
1441 | if (res) | ||
1442 | buf[res-1] = '\n'; /* eat the leftover space */ | ||
1443 | rtnl_unlock(); | ||
1444 | return res; | ||
1445 | } | ||
1446 | |||
1447 | /* | ||
1448 | * Set the queue_ids of the slaves in the current bond. The bond | ||
1449 | * interface must be enslaved for this to work. | ||
1450 | */ | ||
1451 | static ssize_t bonding_store_queue_id(struct device *d, | ||
1452 | struct device_attribute *attr, | ||
1453 | const char *buffer, size_t count) | ||
1454 | { | ||
1455 | struct slave *slave, *update_slave; | ||
1456 | struct bonding *bond = to_bond(d); | ||
1457 | u16 qid; | ||
1458 | int i, ret = count; | ||
1459 | char *delim; | ||
1460 | struct net_device *sdev = NULL; | ||
1461 | |||
1462 | if (!rtnl_trylock()) | ||
1463 | return restart_syscall(); | ||
1464 | |||
1465 | /* delim will point to queue id if successful */ | ||
1466 | delim = strchr(buffer, ':'); | ||
1467 | if (!delim) | ||
1468 | goto err_no_cmd; | ||
1469 | |||
1470 | /* | ||
1471 | * Terminate string that points to device name and bump it | ||
1472 | * up one, so we can read the queue id there. | ||
1473 | */ | ||
1474 | *delim = '\0'; | ||
1475 | if (sscanf(++delim, "%hd\n", &qid) != 1) | ||
1476 | goto err_no_cmd; | ||
1477 | |||
1478 | /* Check buffer length, valid ifname and queue id */ | ||
1479 | if (strlen(buffer) > IFNAMSIZ || | ||
1480 | !dev_valid_name(buffer) || | ||
1481 | qid > bond->params.tx_queues) | ||
1482 | goto err_no_cmd; | ||
1483 | |||
1484 | /* Get the pointer to that interface if it exists */ | ||
1485 | sdev = __dev_get_by_name(dev_net(bond->dev), buffer); | ||
1486 | if (!sdev) | ||
1487 | goto err_no_cmd; | ||
1488 | |||
1489 | read_lock(&bond->lock); | ||
1490 | |||
1491 | /* Search for thes slave and check for duplicate qids */ | ||
1492 | update_slave = NULL; | ||
1493 | bond_for_each_slave(bond, slave, i) { | ||
1494 | if (sdev == slave->dev) | ||
1495 | /* | ||
1496 | * We don't need to check the matching | ||
1497 | * slave for dups, since we're overwriting it | ||
1498 | */ | ||
1499 | update_slave = slave; | ||
1500 | else if (qid && qid == slave->queue_id) { | ||
1501 | goto err_no_cmd_unlock; | ||
1502 | } | ||
1503 | } | ||
1504 | |||
1505 | if (!update_slave) | ||
1506 | goto err_no_cmd_unlock; | ||
1507 | |||
1508 | /* Actually set the qids for the slave */ | ||
1509 | update_slave->queue_id = qid; | ||
1510 | |||
1511 | read_unlock(&bond->lock); | ||
1512 | out: | ||
1513 | rtnl_unlock(); | ||
1514 | return ret; | ||
1515 | |||
1516 | err_no_cmd_unlock: | ||
1517 | read_unlock(&bond->lock); | ||
1518 | err_no_cmd: | ||
1519 | pr_info("invalid input for queue_id set for %s.\n", | ||
1520 | bond->dev->name); | ||
1521 | ret = -EPERM; | ||
1522 | goto out; | ||
1523 | } | ||
1524 | |||
1525 | static DEVICE_ATTR(queue_id, S_IRUGO | S_IWUSR, bonding_show_queue_id, | ||
1526 | bonding_store_queue_id); | ||
1527 | |||
1528 | |||
1529 | /* | ||
1530 | * Show and set the all_slaves_active flag. | ||
1531 | */ | ||
1532 | static ssize_t bonding_show_slaves_active(struct device *d, | ||
1533 | struct device_attribute *attr, | ||
1534 | char *buf) | ||
1535 | { | ||
1536 | struct bonding *bond = to_bond(d); | ||
1537 | |||
1538 | return sprintf(buf, "%d\n", bond->params.all_slaves_active); | ||
1539 | } | ||
1540 | |||
1541 | static ssize_t bonding_store_slaves_active(struct device *d, | ||
1542 | struct device_attribute *attr, | ||
1543 | const char *buf, size_t count) | ||
1544 | { | ||
1545 | int i, new_value, ret = count; | ||
1546 | struct bonding *bond = to_bond(d); | ||
1547 | struct slave *slave; | ||
1548 | |||
1549 | if (sscanf(buf, "%d", &new_value) != 1) { | ||
1550 | pr_err("%s: no all_slaves_active value specified.\n", | ||
1551 | bond->dev->name); | ||
1552 | ret = -EINVAL; | ||
1553 | goto out; | ||
1554 | } | ||
1555 | |||
1556 | if (new_value == bond->params.all_slaves_active) | ||
1557 | goto out; | ||
1558 | |||
1559 | if ((new_value == 0) || (new_value == 1)) { | ||
1560 | bond->params.all_slaves_active = new_value; | ||
1561 | } else { | ||
1562 | pr_info("%s: Ignoring invalid all_slaves_active value %d.\n", | ||
1563 | bond->dev->name, new_value); | ||
1564 | ret = -EINVAL; | ||
1565 | goto out; | ||
1566 | } | ||
1567 | |||
1568 | bond_for_each_slave(bond, slave, i) { | ||
1569 | if (slave->state == BOND_STATE_BACKUP) { | ||
1570 | if (new_value) | ||
1571 | slave->dev->priv_flags &= ~IFF_SLAVE_INACTIVE; | ||
1572 | else | ||
1573 | slave->dev->priv_flags |= IFF_SLAVE_INACTIVE; | ||
1574 | } | ||
1575 | } | ||
1576 | out: | ||
1577 | return count; | ||
1578 | } | ||
1579 | static DEVICE_ATTR(all_slaves_active, S_IRUGO | S_IWUSR, | ||
1580 | bonding_show_slaves_active, bonding_store_slaves_active); | ||
1476 | 1581 | ||
1477 | static struct attribute *per_bond_attrs[] = { | 1582 | static struct attribute *per_bond_attrs[] = { |
1478 | &dev_attr_slaves.attr, | 1583 | &dev_attr_slaves.attr, |
@@ -1499,6 +1604,8 @@ static struct attribute *per_bond_attrs[] = { | |||
1499 | &dev_attr_ad_actor_key.attr, | 1604 | &dev_attr_ad_actor_key.attr, |
1500 | &dev_attr_ad_partner_key.attr, | 1605 | &dev_attr_ad_partner_key.attr, |
1501 | &dev_attr_ad_partner_mac.attr, | 1606 | &dev_attr_ad_partner_mac.attr, |
1607 | &dev_attr_queue_id.attr, | ||
1608 | &dev_attr_all_slaves_active.attr, | ||
1502 | NULL, | 1609 | NULL, |
1503 | }; | 1610 | }; |
1504 | 1611 | ||
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 2aa336720591..c6fdd851579a 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h | |||
@@ -23,8 +23,8 @@ | |||
23 | #include "bond_3ad.h" | 23 | #include "bond_3ad.h" |
24 | #include "bond_alb.h" | 24 | #include "bond_alb.h" |
25 | 25 | ||
26 | #define DRV_VERSION "3.6.0" | 26 | #define DRV_VERSION "3.7.0" |
27 | #define DRV_RELDATE "September 26, 2009" | 27 | #define DRV_RELDATE "June 2, 2010" |
28 | #define DRV_NAME "bonding" | 28 | #define DRV_NAME "bonding" |
29 | #define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" | 29 | #define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" |
30 | 30 | ||
@@ -60,6 +60,9 @@ | |||
60 | ((mode) == BOND_MODE_TLB) || \ | 60 | ((mode) == BOND_MODE_TLB) || \ |
61 | ((mode) == BOND_MODE_ALB)) | 61 | ((mode) == BOND_MODE_ALB)) |
62 | 62 | ||
63 | #define TX_QUEUE_OVERRIDE(mode) \ | ||
64 | (((mode) == BOND_MODE_ACTIVEBACKUP) || \ | ||
65 | ((mode) == BOND_MODE_ROUNDROBIN)) | ||
63 | /* | 66 | /* |
64 | * Less bad way to call ioctl from within the kernel; this needs to be | 67 | * Less bad way to call ioctl from within the kernel; this needs to be |
65 | * done some other way to get the call out of interrupt context. | 68 | * done some other way to get the call out of interrupt context. |
@@ -131,6 +134,8 @@ struct bond_params { | |||
131 | char primary[IFNAMSIZ]; | 134 | char primary[IFNAMSIZ]; |
132 | int primary_reselect; | 135 | int primary_reselect; |
133 | __be32 arp_targets[BOND_MAX_ARP_TARGETS]; | 136 | __be32 arp_targets[BOND_MAX_ARP_TARGETS]; |
137 | int tx_queues; | ||
138 | int all_slaves_active; | ||
134 | }; | 139 | }; |
135 | 140 | ||
136 | struct bond_parm_tbl { | 141 | struct bond_parm_tbl { |
@@ -159,12 +164,12 @@ struct slave { | |||
159 | s8 link; /* one of BOND_LINK_XXXX */ | 164 | s8 link; /* one of BOND_LINK_XXXX */ |
160 | s8 new_link; | 165 | s8 new_link; |
161 | s8 state; /* one of BOND_STATE_XXXX */ | 166 | s8 state; /* one of BOND_STATE_XXXX */ |
162 | u32 original_flags; | ||
163 | u32 original_mtu; | 167 | u32 original_mtu; |
164 | u32 link_failure_count; | 168 | u32 link_failure_count; |
165 | u8 perm_hwaddr[ETH_ALEN]; | 169 | u8 perm_hwaddr[ETH_ALEN]; |
166 | u16 speed; | 170 | u16 speed; |
167 | u8 duplex; | 171 | u8 duplex; |
172 | u16 queue_id; | ||
168 | struct ad_slave_info ad_info; /* HUGE - better to dynamically alloc */ | 173 | struct ad_slave_info ad_info; /* HUGE - better to dynamically alloc */ |
169 | struct tlb_slave_info tlb_info; | 174 | struct tlb_slave_info tlb_info; |
170 | }; | 175 | }; |
@@ -291,7 +296,8 @@ static inline void bond_set_slave_inactive_flags(struct slave *slave) | |||
291 | struct bonding *bond = netdev_priv(slave->dev->master); | 296 | struct bonding *bond = netdev_priv(slave->dev->master); |
292 | if (!bond_is_lb(bond)) | 297 | if (!bond_is_lb(bond)) |
293 | slave->state = BOND_STATE_BACKUP; | 298 | slave->state = BOND_STATE_BACKUP; |
294 | slave->dev->priv_flags |= IFF_SLAVE_INACTIVE; | 299 | if (!bond->params.all_slaves_active) |
300 | slave->dev->priv_flags |= IFF_SLAVE_INACTIVE; | ||
295 | if (slave_do_arp_validate(bond, slave)) | 301 | if (slave_do_arp_validate(bond, slave)) |
296 | slave->dev->priv_flags |= IFF_SLAVE_NEEDARP; | 302 | slave->dev->priv_flags |= IFF_SLAVE_NEEDARP; |
297 | } | 303 | } |