diff options
Diffstat (limited to 'drivers/net/bonding')
-rw-r--r-- | drivers/net/bonding/bond_main.c | 75 | ||||
-rw-r--r-- | drivers/net/bonding/bond_sysfs.c | 116 | ||||
-rw-r--r-- | drivers/net/bonding/bonding.h | 9 |
3 files changed, 195 insertions, 5 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index f22f6bf43858..1b19276cff12 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; |
@@ -111,6 +112,8 @@ static struct bond_params bonding_defaults; | |||
111 | 112 | ||
112 | module_param(max_bonds, int, 0); | 113 | module_param(max_bonds, int, 0); |
113 | 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)"); | ||
114 | module_param(num_grat_arp, int, 0644); | 117 | module_param(num_grat_arp, int, 0644); |
115 | 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"); |
116 | module_param(num_unsol_na, int, 0644); | 119 | module_param(num_unsol_na, int, 0644); |
@@ -1540,6 +1543,12 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) | |||
1540 | goto err_undo_flags; | 1543 | goto err_undo_flags; |
1541 | } | 1544 | } |
1542 | 1545 | ||
1546 | /* | ||
1547 | * Set the new_slave's queue_id to be zero. Queue ID mapping | ||
1548 | * is set via sysfs or module option if desired. | ||
1549 | */ | ||
1550 | new_slave->queue_id = 0; | ||
1551 | |||
1543 | /* Save slave's original mtu and then set it to match the bond */ | 1552 | /* Save slave's original mtu and then set it to match the bond */ |
1544 | new_slave->original_mtu = slave_dev->mtu; | 1553 | new_slave->original_mtu = slave_dev->mtu; |
1545 | res = dev_set_mtu(slave_dev, bond->dev->mtu); | 1554 | res = dev_set_mtu(slave_dev, bond->dev->mtu); |
@@ -3285,6 +3294,7 @@ static void bond_info_show_slave(struct seq_file *seq, | |||
3285 | else | 3294 | else |
3286 | seq_puts(seq, "Aggregator ID: N/A\n"); | 3295 | seq_puts(seq, "Aggregator ID: N/A\n"); |
3287 | } | 3296 | } |
3297 | seq_printf(seq, "Slave queue ID: %d\n", slave->queue_id); | ||
3288 | } | 3298 | } |
3289 | 3299 | ||
3290 | 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) |
@@ -4421,9 +4431,59 @@ static void bond_set_xmit_hash_policy(struct bonding *bond) | |||
4421 | } | 4431 | } |
4422 | } | 4432 | } |
4423 | 4433 | ||
4434 | /* | ||
4435 | * Lookup the slave that corresponds to a qid | ||
4436 | */ | ||
4437 | static inline int bond_slave_override(struct bonding *bond, | ||
4438 | struct sk_buff *skb) | ||
4439 | { | ||
4440 | int i, res = 1; | ||
4441 | struct slave *slave = NULL; | ||
4442 | struct slave *check_slave; | ||
4443 | |||
4444 | read_lock(&bond->lock); | ||
4445 | |||
4446 | if (!BOND_IS_OK(bond) || !skb->queue_mapping) | ||
4447 | goto out; | ||
4448 | |||
4449 | /* Find out if any slaves have the same mapping as this skb. */ | ||
4450 | bond_for_each_slave(bond, check_slave, i) { | ||
4451 | if (check_slave->queue_id == skb->queue_mapping) { | ||
4452 | slave = check_slave; | ||
4453 | break; | ||
4454 | } | ||
4455 | } | ||
4456 | |||
4457 | /* If the slave isn't UP, use default transmit policy. */ | ||
4458 | if (slave && slave->queue_id && IS_UP(slave->dev) && | ||
4459 | (slave->link == BOND_LINK_UP)) { | ||
4460 | res = bond_dev_queue_xmit(bond, skb, slave->dev); | ||
4461 | } | ||
4462 | |||
4463 | out: | ||
4464 | read_unlock(&bond->lock); | ||
4465 | return res; | ||
4466 | } | ||
4467 | |||
4468 | static u16 bond_select_queue(struct net_device *dev, struct sk_buff *skb) | ||
4469 | { | ||
4470 | /* | ||
4471 | * This helper function exists to help dev_pick_tx get the correct | ||
4472 | * destination queue. Using a helper function skips the a call to | ||
4473 | * skb_tx_hash and will put the skbs in the queue we expect on their | ||
4474 | * way down to the bonding driver. | ||
4475 | */ | ||
4476 | return skb->queue_mapping; | ||
4477 | } | ||
4478 | |||
4424 | static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev) | 4479 | static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev) |
4425 | { | 4480 | { |
4426 | const struct bonding *bond = netdev_priv(dev); | 4481 | struct bonding *bond = netdev_priv(dev); |
4482 | |||
4483 | if (TX_QUEUE_OVERRIDE(bond->params.mode)) { | ||
4484 | if (!bond_slave_override(bond, skb)) | ||
4485 | return NETDEV_TX_OK; | ||
4486 | } | ||
4427 | 4487 | ||
4428 | switch (bond->params.mode) { | 4488 | switch (bond->params.mode) { |
4429 | case BOND_MODE_ROUNDROBIN: | 4489 | case BOND_MODE_ROUNDROBIN: |
@@ -4508,6 +4568,7 @@ static const struct net_device_ops bond_netdev_ops = { | |||
4508 | .ndo_open = bond_open, | 4568 | .ndo_open = bond_open, |
4509 | .ndo_stop = bond_close, | 4569 | .ndo_stop = bond_close, |
4510 | .ndo_start_xmit = bond_start_xmit, | 4570 | .ndo_start_xmit = bond_start_xmit, |
4571 | .ndo_select_queue = bond_select_queue, | ||
4511 | .ndo_get_stats = bond_get_stats, | 4572 | .ndo_get_stats = bond_get_stats, |
4512 | .ndo_do_ioctl = bond_do_ioctl, | 4573 | .ndo_do_ioctl = bond_do_ioctl, |
4513 | .ndo_set_multicast_list = bond_set_multicast_list, | 4574 | .ndo_set_multicast_list = bond_set_multicast_list, |
@@ -4776,6 +4837,13 @@ static int bond_check_params(struct bond_params *params) | |||
4776 | } | 4837 | } |
4777 | } | 4838 | } |
4778 | 4839 | ||
4840 | if (tx_queues < 1 || tx_queues > 255) { | ||
4841 | pr_warning("Warning: tx_queues (%d) should be between " | ||
4842 | "1 and 255, resetting to %d\n", | ||
4843 | tx_queues, BOND_DEFAULT_TX_QUEUES); | ||
4844 | tx_queues = BOND_DEFAULT_TX_QUEUES; | ||
4845 | } | ||
4846 | |||
4779 | if ((all_slaves_active != 0) && (all_slaves_active != 1)) { | 4847 | if ((all_slaves_active != 0) && (all_slaves_active != 1)) { |
4780 | pr_warning("Warning: all_slaves_active module parameter (%d), " | 4848 | pr_warning("Warning: all_slaves_active module parameter (%d), " |
4781 | "not of valid value (0/1), so it was set to " | 4849 | "not of valid value (0/1), so it was set to " |
@@ -4953,6 +5021,7 @@ static int bond_check_params(struct bond_params *params) | |||
4953 | params->primary[0] = 0; | 5021 | params->primary[0] = 0; |
4954 | params->primary_reselect = primary_reselect_value; | 5022 | params->primary_reselect = primary_reselect_value; |
4955 | params->fail_over_mac = fail_over_mac_value; | 5023 | params->fail_over_mac = fail_over_mac_value; |
5024 | params->tx_queues = tx_queues; | ||
4956 | params->all_slaves_active = all_slaves_active; | 5025 | params->all_slaves_active = all_slaves_active; |
4957 | 5026 | ||
4958 | if (primary) { | 5027 | if (primary) { |
@@ -5040,8 +5109,8 @@ int bond_create(struct net *net, const char *name) | |||
5040 | 5109 | ||
5041 | rtnl_lock(); | 5110 | rtnl_lock(); |
5042 | 5111 | ||
5043 | bond_dev = alloc_netdev(sizeof(struct bonding), name ? name : "", | 5112 | bond_dev = alloc_netdev_mq(sizeof(struct bonding), name ? name : "", |
5044 | bond_setup); | 5113 | bond_setup, tx_queues); |
5045 | if (!bond_dev) { | 5114 | if (!bond_dev) { |
5046 | pr_err("%s: eek! can't alloc netdev!\n", name); | 5115 | pr_err("%s: eek! can't alloc netdev!\n", name); |
5047 | rtnl_unlock(); | 5116 | rtnl_unlock(); |
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 066311a5e084..f9a034361a8e 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c | |||
@@ -1412,6 +1412,121 @@ static ssize_t bonding_show_ad_partner_mac(struct device *d, | |||
1412 | 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); |
1413 | 1413 | ||
1414 | /* | 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(); | ||
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 | /* | ||
1415 | * Show and set the all_slaves_active flag. | 1530 | * Show and set the all_slaves_active flag. |
1416 | */ | 1531 | */ |
1417 | static ssize_t bonding_show_slaves_active(struct device *d, | 1532 | static ssize_t bonding_show_slaves_active(struct device *d, |
@@ -1489,6 +1604,7 @@ static struct attribute *per_bond_attrs[] = { | |||
1489 | &dev_attr_ad_actor_key.attr, | 1604 | &dev_attr_ad_actor_key.attr, |
1490 | &dev_attr_ad_partner_key.attr, | 1605 | &dev_attr_ad_partner_key.attr, |
1491 | &dev_attr_ad_partner_mac.attr, | 1606 | &dev_attr_ad_partner_mac.attr, |
1607 | &dev_attr_queue_id.attr, | ||
1492 | &dev_attr_all_slaves_active.attr, | 1608 | &dev_attr_all_slaves_active.attr, |
1493 | NULL, | 1609 | NULL, |
1494 | }; | 1610 | }; |
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index cecdea2a629f..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,7 @@ 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; | ||
134 | int all_slaves_active; | 138 | int all_slaves_active; |
135 | }; | 139 | }; |
136 | 140 | ||
@@ -165,6 +169,7 @@ struct slave { | |||
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 | }; |