extern struct bond_parm_tbl bond_lacp_tbl[];
extern struct bond_parm_tbl xmit_hashtype_tbl[];
extern struct bond_parm_tbl arp_validate_tbl[];
+extern struct bond_parm_tbl fail_over_mac_tbl[];
static int expected_refcount = -1;
-static struct class *netdev_class;
/*--------------------------- Data Structures -----------------------------*/
/* Bonding sysfs lock. Why can't we just use the subsystem lock?
{
char command[IFNAMSIZ + 1] = {0, };
char *ifname;
- int res = count;
+ int rv, res = count;
struct bonding *bond;
- struct bonding *nxt;
- down_write(&(bonding_rwsem));
sscanf(buffer, "%16s", command); /* IFNAMSIZ*/
ifname = command + 1;
if ((strlen(command) <= 1) ||
goto err_no_cmd;
if (command[0] == '+') {
-
- /* Check to see if the bond already exists. */
- list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list)
- if (strnicmp(bond->dev->name, ifname, IFNAMSIZ) == 0) {
- printk(KERN_ERR DRV_NAME
- ": cannot add bond %s; it already exists\n",
- ifname);
- res = -EPERM;
- goto out;
- }
-
printk(KERN_INFO DRV_NAME
": %s is being created...\n", ifname);
- if (bond_create(ifname, &bonding_defaults, &bond)) {
- printk(KERN_INFO DRV_NAME
- ": %s interface already exists. Bond creation failed.\n",
- ifname);
- res = -EPERM;
+ rv = bond_create(ifname, &bonding_defaults);
+ if (rv) {
+ printk(KERN_INFO DRV_NAME ": Bond creation failed.\n");
+ res = rv;
}
goto out;
}
if (command[0] == '-') {
- list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list)
+ rtnl_lock();
+ down_write(&bonding_rwsem);
+
+ list_for_each_entry(bond, &bond_dev_list, bond_list)
if (strnicmp(bond->dev->name, ifname, IFNAMSIZ) == 0) {
- rtnl_lock();
/* check the ref count on the bond's kobject.
* If it's > expected, then there's a file open,
* and we have to fail.
*/
if (atomic_read(&bond->dev->dev.kobj.kref.refcount)
> expected_refcount){
- rtnl_unlock();
printk(KERN_INFO DRV_NAME
": Unable remove bond %s due to open references.\n",
ifname);
res = -EPERM;
- goto out;
+ goto out_unlock;
}
printk(KERN_INFO DRV_NAME
": %s is being deleted...\n",
bond->dev->name);
bond_destroy(bond);
- rtnl_unlock();
- goto out;
+ goto out_unlock;
}
printk(KERN_ERR DRV_NAME
": unable to delete non-existent bond %s\n", ifname);
res = -ENODEV;
- goto out;
+ goto out_unlock;
}
err_no_cmd:
printk(KERN_ERR DRV_NAME
": no command found in bonding_masters. Use +ifname or -ifname.\n");
- res = -EPERM;
+ return -EPERM;
+
+out_unlock:
+ up_write(&bonding_rwsem);
+ rtnl_unlock();
/* Always return either count or an error. If you return 0, you'll
* get called forever, which is bad.
*/
out:
- up_write(&(bonding_rwsem));
return res;
}
/* class attribute for bond_masters file. This ends up in /sys/class/net */
/* Note: We can't hold bond->lock here, as bond_create grabs it. */
+ rtnl_lock();
+ down_write(&(bonding_rwsem));
+
sscanf(buffer, "%16s", command); /* IFNAMSIZ*/
ifname = command + 1;
if ((strlen(command) <= 1) ||
dev->mtu = bond->dev->mtu;
}
}
- rtnl_lock();
res = bond_enslave(bond->dev, dev);
bond_for_each_slave(bond, slave, i)
if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0)
slave->original_mtu = original_mtu;
- rtnl_unlock();
if (res) {
ret = res;
}
if (command[0] == '-') {
dev = NULL;
+ original_mtu = 0;
bond_for_each_slave(bond, slave, i)
if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0) {
dev = slave->dev;
if (dev) {
printk(KERN_INFO DRV_NAME ": %s: Removing slave %s\n",
bond->dev->name, dev->name);
- rtnl_lock();
if (bond->setup_by_slave)
res = bond_release_and_destroy(bond->dev, dev);
else
res = bond_release(bond->dev, dev);
- rtnl_unlock();
if (res) {
ret = res;
goto out;
ret = -EPERM;
out:
+ up_write(&(bonding_rwsem));
+ rtnl_unlock();
return ret;
}
goto out;
}
- new_value = bond_parse_parm((char *)buf, bond_mode_tbl);
+ new_value = bond_parse_parm(buf, bond_mode_tbl);
if (new_value < 0) {
printk(KERN_ERR DRV_NAME
": %s: Ignoring invalid mode value %.*s.\n",
goto out;
}
- new_value = bond_parse_parm((char *)buf, xmit_hashtype_tbl);
+ new_value = bond_parse_parm(buf, xmit_hashtype_tbl);
if (new_value < 0) {
printk(KERN_ERR DRV_NAME
": %s: Ignoring invalid xmit hash policy value %.*s.\n",
int new_value;
struct bonding *bond = to_bond(d);
- new_value = bond_parse_parm((char *)buf, arp_validate_tbl);
+ new_value = bond_parse_parm(buf, arp_validate_tbl);
if (new_value < 0) {
printk(KERN_ERR DRV_NAME
": %s: Ignoring invalid arp_validate value %s\n",
{
struct bonding *bond = to_bond(d);
- return sprintf(buf, "%d\n", bond->params.fail_over_mac) + 1;
+ return sprintf(buf, "%s %d\n",
+ fail_over_mac_tbl[bond->params.fail_over_mac].modename,
+ bond->params.fail_over_mac);
}
static ssize_t bonding_store_fail_over_mac(struct device *d, struct device_attribute *attr, const char *buf, size_t count)
{
int new_value;
- int ret = count;
struct bonding *bond = to_bond(d);
if (bond->slave_cnt != 0) {
printk(KERN_ERR DRV_NAME
": %s: Can't alter fail_over_mac with slaves in bond.\n",
bond->dev->name);
- ret = -EPERM;
- goto out;
+ return -EPERM;
}
- if (sscanf(buf, "%d", &new_value) != 1) {
+ new_value = bond_parse_parm(buf, fail_over_mac_tbl);
+ if (new_value < 0) {
printk(KERN_ERR DRV_NAME
- ": %s: no fail_over_mac value specified.\n",
- bond->dev->name);
- ret = -EINVAL;
- goto out;
+ ": %s: Ignoring invalid fail_over_mac value %s.\n",
+ bond->dev->name, buf);
+ return -EINVAL;
}
- if ((new_value == 0) || (new_value == 1)) {
- bond->params.fail_over_mac = new_value;
- printk(KERN_INFO DRV_NAME ": %s: Setting fail_over_mac to %d.\n",
- bond->dev->name, new_value);
- } else {
- printk(KERN_INFO DRV_NAME
- ": %s: Ignoring invalid fail_over_mac value %d.\n",
- bond->dev->name, new_value);
- }
-out:
- return ret;
+ bond->params.fail_over_mac = new_value;
+ printk(KERN_INFO DRV_NAME ": %s: Setting fail_over_mac to %s (%d).\n",
+ bond->dev->name, fail_over_mac_tbl[new_value].modename,
+ new_value);
+
+ return count;
}
static DEVICE_ATTR(fail_over_mac, S_IRUGO | S_IWUSR, bonding_show_fail_over_mac, bonding_store_fail_over_mac);
goto out;
}
- new_value = bond_parse_parm((char *)buf, bond_lacp_tbl);
+ new_value = bond_parse_parm(buf, bond_lacp_tbl);
if ((new_value == 1) || (new_value == 0)) {
bond->params.lacp_fast = new_value;
}
static DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bonding_store_lacp);
+/*
+ * Show and set the number of grat ARP to send after a failover event.
+ */
+static ssize_t bonding_show_n_grat_arp(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct bonding *bond = to_bond(d);
+
+ return sprintf(buf, "%d\n", bond->params.num_grat_arp);
+}
+
+static ssize_t bonding_store_n_grat_arp(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int new_value, ret = count;
+ struct bonding *bond = to_bond(d);
+
+ if (sscanf(buf, "%d", &new_value) != 1) {
+ printk(KERN_ERR DRV_NAME
+ ": %s: no num_grat_arp value specified.\n",
+ bond->dev->name);
+ ret = -EINVAL;
+ goto out;
+ }
+ if (new_value < 0 || new_value > 255) {
+ printk(KERN_ERR DRV_NAME
+ ": %s: Invalid num_grat_arp value %d not in range 0-255; rejected.\n",
+ bond->dev->name, new_value);
+ ret = -EINVAL;
+ goto out;
+ } else {
+ bond->params.num_grat_arp = new_value;
+ }
+out:
+ return ret;
+}
+static DEVICE_ATTR(num_grat_arp, S_IRUGO | S_IWUSR, bonding_show_n_grat_arp, bonding_store_n_grat_arp);
/*
* Show and set the MII monitor interval. There are two tricky bits
* here. First, if MII monitoring is activated, then we must disable
struct slave *slave;
struct bonding *bond = to_bond(d);
- write_lock_bh(&bond->lock);
+ rtnl_lock();
+ read_lock(&bond->lock);
+ write_lock_bh(&bond->curr_slave_lock);
+
if (!USES_PRIMARY(bond->params.mode)) {
printk(KERN_INFO DRV_NAME
": %s: Unable to set primary slave; %s is in mode %d\n",
}
}
out:
- write_unlock_bh(&bond->lock);
-
+ write_unlock_bh(&bond->curr_slave_lock);
+ read_unlock(&bond->lock);
rtnl_unlock();
return count;
struct bonding *bond = to_bond(d);
rtnl_lock();
- write_lock_bh(&bond->lock);
+ read_lock(&bond->lock);
+ write_lock_bh(&bond->curr_slave_lock);
if (!USES_PRIMARY(bond->params.mode)) {
printk(KERN_INFO DRV_NAME
}
}
out:
- write_unlock_bh(&bond->lock);
+ write_unlock_bh(&bond->curr_slave_lock);
+ read_unlock(&bond->lock);
rtnl_unlock();
return count;
&dev_attr_updelay.attr,
&dev_attr_lacp_rate.attr,
&dev_attr_xmit_hash_policy.attr,
+ &dev_attr_num_grat_arp.attr,
&dev_attr_miimon.attr,
&dev_attr_primary.attr,
&dev_attr_use_carrier.attr,
*/
int bond_create_sysfs(void)
{
- int ret = 0;
- struct bonding *firstbond;
-
- init_rwsem(&bonding_rwsem);
-
- /* get the netdev class pointer */
- firstbond = container_of(bond_dev_list.next, struct bonding, bond_list);
- if (!firstbond)
- return -ENODEV;
-
- netdev_class = firstbond->dev->dev.class;
- if (!netdev_class)
- return -ENODEV;
+ int ret;
- ret = class_create_file(netdev_class, &class_attr_bonding_masters);
+ ret = netdev_class_create_file(&class_attr_bonding_masters);
/*
* Permit multiple loads of the module by ignoring failures to
* create the bonding_masters sysfs file. Bonding devices
* configure multiple bonding devices.
*/
if (ret == -EEXIST) {
- netdev_class = NULL;
- return 0;
+ /* Is someone being kinky and naming a device bonding_master? */
+ if (__dev_get_by_name(&init_net,
+ class_attr_bonding_masters.attr.name))
+ printk(KERN_ERR
+ "network device named %s already exists in sysfs",
+ class_attr_bonding_masters.attr.name);
}
return ret;
*/
void bond_destroy_sysfs(void)
{
- if (netdev_class)
- class_remove_file(netdev_class, &class_attr_bonding_masters);
+ netdev_class_remove_file(&class_attr_bonding_masters);
}
/*