From eecdaa6e20284efbe9e76eebd44eac2b22f7b5d7 Mon Sep 17 00:00:00 2001 From: "sfeldma@cumulusnetworks.com" Date: Thu, 12 Dec 2013 14:09:55 -0800 Subject: [PATCH 1/8] bonding: add miimon netlink support Add IFLA_BOND_MIIMON to allow get/set of bonding parameter miimon via netlink. Signed-off-by: Scott Feldman Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/bonding/bond_netlink.c | 32 ++++++++++++++---- drivers/net/bonding/bond_options.c | 42 +++++++++++++++++++++++ drivers/net/bonding/bond_sysfs.c | 53 ++++++------------------------ drivers/net/bonding/bonding.h | 1 + include/uapi/linux/if_link.h | 1 + 5 files changed, 80 insertions(+), 49 deletions(-) diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index 40e7b1cb4aeaa..28a88beb749b1 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -1,6 +1,7 @@ /* * drivers/net/bond/bond_netlink.c - Netlink interface for bonding * Copyright (c) 2013 Jiri Pirko + * Copyright (c) 2013 Scott Feldman * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,6 +24,7 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = { [IFLA_BOND_MODE] = { .type = NLA_U8 }, [IFLA_BOND_ACTIVE_SLAVE] = { .type = NLA_U32 }, + [IFLA_BOND_MIIMON] = { .type = NLA_U32 }, }; static int bond_validate(struct nlattr *tb[], struct nlattr *data[]) @@ -42,14 +44,17 @@ static int bond_changelink(struct net_device *bond_dev, struct bonding *bond = netdev_priv(bond_dev); int err; - if (data && data[IFLA_BOND_MODE]) { + if (!data) + return 0; + + if (data[IFLA_BOND_MODE]) { int mode = nla_get_u8(data[IFLA_BOND_MODE]); err = bond_option_mode_set(bond, mode); if (err) return err; } - if (data && data[IFLA_BOND_ACTIVE_SLAVE]) { + if (data[IFLA_BOND_ACTIVE_SLAVE]) { int ifindex = nla_get_u32(data[IFLA_BOND_ACTIVE_SLAVE]); struct net_device *slave_dev; @@ -65,6 +70,13 @@ static int bond_changelink(struct net_device *bond_dev, if (err) return err; } + if (data[IFLA_BOND_MIIMON]) { + int miimon = nla_get_u32(data[IFLA_BOND_MIIMON]); + + err = bond_option_miimon_set(bond, miimon); + if (err) + return err; + } return 0; } @@ -83,7 +95,9 @@ static int bond_newlink(struct net *src_net, struct net_device *bond_dev, static size_t bond_get_size(const struct net_device *bond_dev) { return nla_total_size(sizeof(u8)) + /* IFLA_BOND_MODE */ - nla_total_size(sizeof(u32)); /* IFLA_BOND_ACTIVE_SLAVE */ + nla_total_size(sizeof(u32)) + /* IFLA_BOND_ACTIVE_SLAVE */ + nla_total_size(sizeof(u32)) + /* IFLA_BOND_MIIMON */ + 0; } static int bond_fill_info(struct sk_buff *skb, @@ -92,10 +106,16 @@ static int bond_fill_info(struct sk_buff *skb, struct bonding *bond = netdev_priv(bond_dev); struct net_device *slave_dev = bond_option_active_slave_get(bond); - if (nla_put_u8(skb, IFLA_BOND_MODE, bond->params.mode) || - (slave_dev && - nla_put_u32(skb, IFLA_BOND_ACTIVE_SLAVE, slave_dev->ifindex))) + if (nla_put_u8(skb, IFLA_BOND_MODE, bond->params.mode)) goto nla_put_failure; + + if (slave_dev && + nla_put_u32(skb, IFLA_BOND_ACTIVE_SLAVE, slave_dev->ifindex)) + goto nla_put_failure; + + if (nla_put_u32(skb, IFLA_BOND_MIIMON, bond->params.miimon)) + goto nla_put_failure; + return 0; nla_put_failure: diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index ea6f640782b74..8ae42d36f11f1 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -1,6 +1,7 @@ /* * drivers/net/bond/bond_options.c - bonding options * Copyright (c) 2013 Jiri Pirko + * Copyright (c) 2013 Scott Feldman * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -145,3 +146,44 @@ int bond_option_active_slave_set(struct bonding *bond, unblock_netpoll_tx(); return ret; } + +int bond_option_miimon_set(struct bonding *bond, int miimon) +{ + if (miimon < 0) { + pr_err("%s: Invalid miimon value %d not in range %d-%d; rejected.\n", + bond->dev->name, miimon, 0, INT_MAX); + return -EINVAL; + } + pr_info("%s: Setting MII monitoring interval to %d.\n", + bond->dev->name, miimon); + bond->params.miimon = miimon; + if (bond->params.updelay) + pr_info("%s: Note: Updating updelay (to %d) since it is a multiple of the miimon value.\n", + bond->dev->name, + bond->params.updelay * bond->params.miimon); + if (bond->params.downdelay) + pr_info("%s: Note: Updating downdelay (to %d) since it is a multiple of the miimon value.\n", + bond->dev->name, + bond->params.downdelay * bond->params.miimon); + if (miimon && bond->params.arp_interval) { + pr_info("%s: MII monitoring cannot be used with ARP monitoring. Disabling ARP monitoring...\n", + bond->dev->name); + bond->params.arp_interval = 0; + if (bond->params.arp_validate) + bond->params.arp_validate = BOND_ARP_VALIDATE_NONE; + } + if (bond->dev->flags & IFF_UP) { + /* If the interface is up, we may need to fire off + * the MII timer. If the interface is down, the + * timer will get fired off when the open function + * is called. + */ + if (!miimon) { + cancel_delayed_work_sync(&bond->mii_work); + } else { + cancel_delayed_work_sync(&bond->arp_work); + queue_delayed_work(bond->wq, &bond->mii_work, 0); + } + } + return 0; +} diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index e46467683e822..d6d6fc7812d5a 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -970,55 +970,22 @@ static ssize_t bonding_store_miimon(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - int new_value, ret = count; + int new_value, ret; struct bonding *bond = to_bond(d); - if (!rtnl_trylock()) - return restart_syscall(); if (sscanf(buf, "%d", &new_value) != 1) { pr_err("%s: no miimon value specified.\n", bond->dev->name); - ret = -EINVAL; - goto out; - } - if (new_value < 0) { - pr_err("%s: Invalid miimon value %d not in range %d-%d; rejected.\n", - bond->dev->name, new_value, 0, INT_MAX); - ret = -EINVAL; - goto out; - } - pr_info("%s: Setting MII monitoring interval to %d.\n", - bond->dev->name, new_value); - bond->params.miimon = new_value; - if (bond->params.updelay) - pr_info("%s: Note: Updating updelay (to %d) since it is a multiple of the miimon value.\n", - bond->dev->name, - bond->params.updelay * bond->params.miimon); - if (bond->params.downdelay) - pr_info("%s: Note: Updating downdelay (to %d) since it is a multiple of the miimon value.\n", - bond->dev->name, - bond->params.downdelay * bond->params.miimon); - if (new_value && bond->params.arp_interval) { - pr_info("%s: MII monitoring cannot be used with ARP monitoring. Disabling ARP monitoring...\n", - bond->dev->name); - bond->params.arp_interval = 0; - if (bond->params.arp_validate) - bond->params.arp_validate = BOND_ARP_VALIDATE_NONE; - } - if (bond->dev->flags & IFF_UP) { - /* If the interface is up, we may need to fire off - * the MII timer. If the interface is down, the - * timer will get fired off when the open function - * is called. - */ - if (!new_value) { - cancel_delayed_work_sync(&bond->mii_work); - } else { - cancel_delayed_work_sync(&bond->arp_work); - queue_delayed_work(bond->wq, &bond->mii_work, 0); - } + return -EINVAL; } -out: + + if (!rtnl_trylock()) + return restart_syscall(); + + ret = bond_option_miimon_set(bond, new_value); + if (!ret) + ret = count; + rtnl_unlock(); return ret; } diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index a74c92c83eadd..b146479d58592 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -439,6 +439,7 @@ int bond_netlink_init(void); void bond_netlink_fini(void); int bond_option_mode_set(struct bonding *bond, int mode); int bond_option_active_slave_set(struct bonding *bond, struct net_device *slave_dev); +int bond_option_miimon_set(struct bonding *bond, int miimon); struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond); struct net_device *bond_option_active_slave_get(struct bonding *bond); diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 6db460121f848..739b2db3f0352 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -331,6 +331,7 @@ enum { IFLA_BOND_UNSPEC, IFLA_BOND_MODE, IFLA_BOND_ACTIVE_SLAVE, + IFLA_BOND_MIIMON, __IFLA_BOND_MAX, }; From 25852e29dfc58d249ad0db235996b36c33db6d61 Mon Sep 17 00:00:00 2001 From: "sfeldma@cumulusnetworks.com" Date: Thu, 12 Dec 2013 14:10:02 -0800 Subject: [PATCH 2/8] bonding: add updelay netlink support Add IFLA_BOND_UPDELAY to allow get/set of bonding parameter updelay via netlink. Signed-off-by: Scott Feldman Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/bonding/bond_netlink.c | 13 +++++++++ drivers/net/bonding/bond_options.c | 29 +++++++++++++++++++++ drivers/net/bonding/bond_sysfs.c | 42 +++++++----------------------- drivers/net/bonding/bonding.h | 1 + include/uapi/linux/if_link.h | 1 + 5 files changed, 54 insertions(+), 32 deletions(-) diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index 28a88beb749b1..086cf4f5f0a6e 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -25,6 +25,7 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = { [IFLA_BOND_MODE] = { .type = NLA_U8 }, [IFLA_BOND_ACTIVE_SLAVE] = { .type = NLA_U32 }, [IFLA_BOND_MIIMON] = { .type = NLA_U32 }, + [IFLA_BOND_UPDELAY] = { .type = NLA_U32 }, }; static int bond_validate(struct nlattr *tb[], struct nlattr *data[]) @@ -77,6 +78,13 @@ static int bond_changelink(struct net_device *bond_dev, if (err) return err; } + if (data[IFLA_BOND_UPDELAY]) { + int updelay = nla_get_u32(data[IFLA_BOND_UPDELAY]); + + err = bond_option_updelay_set(bond, updelay); + if (err) + return err; + } return 0; } @@ -97,6 +105,7 @@ static size_t bond_get_size(const struct net_device *bond_dev) return nla_total_size(sizeof(u8)) + /* IFLA_BOND_MODE */ nla_total_size(sizeof(u32)) + /* IFLA_BOND_ACTIVE_SLAVE */ nla_total_size(sizeof(u32)) + /* IFLA_BOND_MIIMON */ + nla_total_size(sizeof(u32)) + /* IFLA_BOND_UPDELAY */ 0; } @@ -116,6 +125,10 @@ static int bond_fill_info(struct sk_buff *skb, if (nla_put_u32(skb, IFLA_BOND_MIIMON, bond->params.miimon)) goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BOND_UPDELAY, + bond->params.updelay * bond->params.miimon)) + goto nla_put_failure; + return 0; nla_put_failure: diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index 8ae42d36f11f1..ae94b847ffcc4 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -187,3 +187,32 @@ int bond_option_miimon_set(struct bonding *bond, int miimon) } return 0; } + +int bond_option_updelay_set(struct bonding *bond, int updelay) +{ + if (!(bond->params.miimon)) { + pr_err("%s: Unable to set up delay as MII monitoring is disabled\n", + bond->dev->name); + return -EPERM; + } + + if (updelay < 0) { + pr_err("%s: Invalid up delay value %d not in range %d-%d; rejected.\n", + bond->dev->name, updelay, 0, INT_MAX); + return -EINVAL; + } else { + if ((updelay % bond->params.miimon) != 0) { + pr_warn("%s: Warning: up delay (%d) is not a multiple of miimon (%d), updelay rounded to %d ms\n", + bond->dev->name, updelay, + bond->params.miimon, + (updelay / bond->params.miimon) * + bond->params.miimon); + } + bond->params.updelay = updelay / bond->params.miimon; + pr_info("%s: Setting up delay to %d.\n", + bond->dev->name, + bond->params.updelay * bond->params.miimon); + } + + return 0; +} diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index d6d6fc7812d5a..4dcbec4e07c02 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -747,44 +747,22 @@ static ssize_t bonding_store_updelay(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - int new_value, ret = count; + int new_value, ret; struct bonding *bond = to_bond(d); - if (!rtnl_trylock()) - return restart_syscall(); - if (!(bond->params.miimon)) { - pr_err("%s: Unable to set up delay as MII monitoring is disabled\n", - bond->dev->name); - ret = -EPERM; - goto out; - } - if (sscanf(buf, "%d", &new_value) != 1) { pr_err("%s: no up delay value specified.\n", - bond->dev->name); - ret = -EINVAL; - goto out; - } - if (new_value < 0) { - pr_err("%s: Invalid up delay value %d not in range %d-%d; rejected.\n", - bond->dev->name, new_value, 0, INT_MAX); - ret = -EINVAL; - goto out; - } else { - if ((new_value % bond->params.miimon) != 0) { - pr_warning("%s: Warning: up delay (%d) is not a multiple of miimon (%d), updelay rounded to %d ms\n", - bond->dev->name, new_value, - bond->params.miimon, - (new_value / bond->params.miimon) * - bond->params.miimon); - } - bond->params.updelay = new_value / bond->params.miimon; - pr_info("%s: Setting up delay to %d.\n", - bond->dev->name, - bond->params.updelay * bond->params.miimon); + bond->dev->name); + return -EINVAL; } -out: + if (!rtnl_trylock()) + return restart_syscall(); + + ret = bond_option_updelay_set(bond, new_value); + if (!ret) + ret = count; + rtnl_unlock(); return ret; } diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index b146479d58592..8a91f7187e51e 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -440,6 +440,7 @@ void bond_netlink_fini(void); int bond_option_mode_set(struct bonding *bond, int mode); int bond_option_active_slave_set(struct bonding *bond, struct net_device *slave_dev); int bond_option_miimon_set(struct bonding *bond, int miimon); +int bond_option_updelay_set(struct bonding *bond, int updelay); struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond); struct net_device *bond_option_active_slave_get(struct bonding *bond); diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 739b2db3f0352..7588c8120e7ff 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -332,6 +332,7 @@ enum { IFLA_BOND_MODE, IFLA_BOND_ACTIVE_SLAVE, IFLA_BOND_MIIMON, + IFLA_BOND_UPDELAY, __IFLA_BOND_MAX, }; From c7461f9bf5a11bf88fdbd05b26c6d55b77dcd46d Mon Sep 17 00:00:00 2001 From: "sfeldma@cumulusnetworks.com" Date: Thu, 12 Dec 2013 14:10:09 -0800 Subject: [PATCH 3/8] bonding: add downdelay netlink support Add IFLA_BOND_DOWNDELAY to allow get/set of bonding parameter downdelay via netlink. Signed-off-by: Scott Feldman Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/bonding/bond_netlink.c | 13 ++++++++++ drivers/net/bonding/bond_options.c | 29 ++++++++++++++++++++++ drivers/net/bonding/bond_sysfs.c | 39 ++++++------------------------ drivers/net/bonding/bonding.h | 1 + include/uapi/linux/if_link.h | 1 + 5 files changed, 52 insertions(+), 31 deletions(-) diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index 086cf4f5f0a6e..a0a2e8c32fe53 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -26,6 +26,7 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = { [IFLA_BOND_ACTIVE_SLAVE] = { .type = NLA_U32 }, [IFLA_BOND_MIIMON] = { .type = NLA_U32 }, [IFLA_BOND_UPDELAY] = { .type = NLA_U32 }, + [IFLA_BOND_DOWNDELAY] = { .type = NLA_U32 }, }; static int bond_validate(struct nlattr *tb[], struct nlattr *data[]) @@ -85,6 +86,13 @@ static int bond_changelink(struct net_device *bond_dev, if (err) return err; } + if (data[IFLA_BOND_DOWNDELAY]) { + int downdelay = nla_get_u32(data[IFLA_BOND_DOWNDELAY]); + + err = bond_option_downdelay_set(bond, downdelay); + if (err) + return err; + } return 0; } @@ -106,6 +114,7 @@ static size_t bond_get_size(const struct net_device *bond_dev) nla_total_size(sizeof(u32)) + /* IFLA_BOND_ACTIVE_SLAVE */ nla_total_size(sizeof(u32)) + /* IFLA_BOND_MIIMON */ nla_total_size(sizeof(u32)) + /* IFLA_BOND_UPDELAY */ + nla_total_size(sizeof(u32)) + /* IFLA_BOND_DOWNDELAY */ 0; } @@ -129,6 +138,10 @@ static int bond_fill_info(struct sk_buff *skb, bond->params.updelay * bond->params.miimon)) goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BOND_DOWNDELAY, + bond->params.downdelay * bond->params.miimon)) + goto nla_put_failure; + return 0; nla_put_failure: diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index ae94b847ffcc4..2914d649ee348 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -216,3 +216,32 @@ int bond_option_updelay_set(struct bonding *bond, int updelay) return 0; } + +int bond_option_downdelay_set(struct bonding *bond, int downdelay) +{ + if (!(bond->params.miimon)) { + pr_err("%s: Unable to set down delay as MII monitoring is disabled\n", + bond->dev->name); + return -EPERM; + } + + if (downdelay < 0) { + pr_err("%s: Invalid down delay value %d not in range %d-%d; rejected.\n", + bond->dev->name, downdelay, 0, INT_MAX); + return -EINVAL; + } else { + if ((downdelay % bond->params.miimon) != 0) { + pr_warn("%s: Warning: down delay (%d) is not a multiple of miimon (%d), delay rounded to %d ms\n", + bond->dev->name, downdelay, + bond->params.miimon, + (downdelay / bond->params.miimon) * + bond->params.miimon); + } + bond->params.downdelay = downdelay / bond->params.miimon; + pr_info("%s: Setting down delay to %d.\n", + bond->dev->name, + bond->params.downdelay * bond->params.miimon); + } + + return 0; +} diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 4dcbec4e07c02..bec20bc08d31b 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -689,44 +689,21 @@ static ssize_t bonding_store_downdelay(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - int new_value, ret = count; + int new_value, ret; struct bonding *bond = to_bond(d); - if (!rtnl_trylock()) - return restart_syscall(); - if (!(bond->params.miimon)) { - pr_err("%s: Unable to set down delay as MII monitoring is disabled\n", - bond->dev->name); - ret = -EPERM; - goto out; - } - if (sscanf(buf, "%d", &new_value) != 1) { pr_err("%s: no down delay value specified.\n", bond->dev->name); - ret = -EINVAL; - goto out; + return -EINVAL; } - if (new_value < 0) { - pr_err("%s: Invalid down delay value %d not in range %d-%d; rejected.\n", - bond->dev->name, new_value, 0, INT_MAX); - ret = -EINVAL; - goto out; - } else { - if ((new_value % bond->params.miimon) != 0) { - pr_warning("%s: Warning: down delay (%d) is not a multiple of miimon (%d), delay rounded to %d ms\n", - bond->dev->name, new_value, - bond->params.miimon, - (new_value / bond->params.miimon) * - bond->params.miimon); - } - bond->params.downdelay = new_value / bond->params.miimon; - pr_info("%s: Setting down delay to %d.\n", - bond->dev->name, - bond->params.downdelay * bond->params.miimon); - } + if (!rtnl_trylock()) + return restart_syscall(); + + ret = bond_option_downdelay_set(bond, new_value); + if (!ret) + ret = count; -out: rtnl_unlock(); return ret; } diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 8a91f7187e51e..f5749b18d1681 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -441,6 +441,7 @@ int bond_option_mode_set(struct bonding *bond, int mode); int bond_option_active_slave_set(struct bonding *bond, struct net_device *slave_dev); int bond_option_miimon_set(struct bonding *bond, int miimon); int bond_option_updelay_set(struct bonding *bond, int updelay); +int bond_option_downdelay_set(struct bonding *bond, int downdelay); struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond); struct net_device *bond_option_active_slave_get(struct bonding *bond); diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 7588c8120e7ff..f955067777101 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -333,6 +333,7 @@ enum { IFLA_BOND_ACTIVE_SLAVE, IFLA_BOND_MIIMON, IFLA_BOND_UPDELAY, + IFLA_BOND_DOWNDELAY, __IFLA_BOND_MAX, }; From 9f53e14e86c46a2300f17309f6308ad0dfbb53ff Mon Sep 17 00:00:00 2001 From: "sfeldma@cumulusnetworks.com" Date: Thu, 12 Dec 2013 14:10:16 -0800 Subject: [PATCH 4/8] bonding: add use_carrier netlink support Add IFLA_BOND_USE_CARRIER to allow get/set of bonding parameter use_carrier via netlink. Signed-off-by: Scott Feldman Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/bonding/bond_netlink.c | 12 ++++++++++++ drivers/net/bonding/bond_options.c | 14 ++++++++++++++ drivers/net/bonding/bond_sysfs.c | 24 +++++++++++------------- drivers/net/bonding/bonding.h | 1 + include/uapi/linux/if_link.h | 1 + 5 files changed, 39 insertions(+), 13 deletions(-) diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index a0a2e8c32fe53..7edf6399cea24 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -27,6 +27,7 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = { [IFLA_BOND_MIIMON] = { .type = NLA_U32 }, [IFLA_BOND_UPDELAY] = { .type = NLA_U32 }, [IFLA_BOND_DOWNDELAY] = { .type = NLA_U32 }, + [IFLA_BOND_USE_CARRIER] = { .type = NLA_U8 }, }; static int bond_validate(struct nlattr *tb[], struct nlattr *data[]) @@ -93,6 +94,13 @@ static int bond_changelink(struct net_device *bond_dev, if (err) return err; } + if (data[IFLA_BOND_USE_CARRIER]) { + int use_carrier = nla_get_u8(data[IFLA_BOND_USE_CARRIER]); + + err = bond_option_use_carrier_set(bond, use_carrier); + if (err) + return err; + } return 0; } @@ -115,6 +123,7 @@ static size_t bond_get_size(const struct net_device *bond_dev) nla_total_size(sizeof(u32)) + /* IFLA_BOND_MIIMON */ nla_total_size(sizeof(u32)) + /* IFLA_BOND_UPDELAY */ nla_total_size(sizeof(u32)) + /* IFLA_BOND_DOWNDELAY */ + nla_total_size(sizeof(u8)) + /* IFLA_BOND_USE_CARRIER */ 0; } @@ -142,6 +151,9 @@ static int bond_fill_info(struct sk_buff *skb, bond->params.downdelay * bond->params.miimon)) goto nla_put_failure; + if (nla_put_u8(skb, IFLA_BOND_USE_CARRIER, bond->params.use_carrier)) + goto nla_put_failure; + return 0; nla_put_failure: diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index 2914d649ee348..6fc7bbf0b85f9 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -245,3 +245,17 @@ int bond_option_downdelay_set(struct bonding *bond, int downdelay) return 0; } + +int bond_option_use_carrier_set(struct bonding *bond, int use_carrier) +{ + if ((use_carrier == 0) || (use_carrier == 1)) { + bond->params.use_carrier = use_carrier; + pr_info("%s: Setting use_carrier to %d.\n", + bond->dev->name, use_carrier); + } else { + pr_info("%s: Ignoring invalid use_carrier value %d.\n", + bond->dev->name, use_carrier); + } + + return 0; +} diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index bec20bc08d31b..114760af9a6db 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -1097,25 +1097,23 @@ static ssize_t bonding_store_carrier(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - int new_value, ret = count; + int new_value, ret; struct bonding *bond = to_bond(d); - if (sscanf(buf, "%d", &new_value) != 1) { pr_err("%s: no use_carrier value specified.\n", bond->dev->name); - ret = -EINVAL; - goto out; - } - if ((new_value == 0) || (new_value == 1)) { - bond->params.use_carrier = new_value; - pr_info("%s: Setting use_carrier to %d.\n", - bond->dev->name, new_value); - } else { - pr_info("%s: Ignoring invalid use_carrier value %d.\n", - bond->dev->name, new_value); + return -EINVAL; } -out: + + if (!rtnl_trylock()) + return restart_syscall(); + + ret = bond_option_use_carrier_set(bond, new_value); + if (!ret) + ret = count; + + rtnl_unlock(); return ret; } static DEVICE_ATTR(use_carrier, S_IRUGO | S_IWUSR, diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index f5749b18d1681..df159da8db309 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -442,6 +442,7 @@ int bond_option_active_slave_set(struct bonding *bond, struct net_device *slave_ int bond_option_miimon_set(struct bonding *bond, int miimon); int bond_option_updelay_set(struct bonding *bond, int updelay); int bond_option_downdelay_set(struct bonding *bond, int downdelay); +int bond_option_use_carrier_set(struct bonding *bond, int use_carrier); struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond); struct net_device *bond_option_active_slave_get(struct bonding *bond); diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index f955067777101..77c41bda36a42 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -334,6 +334,7 @@ enum { IFLA_BOND_MIIMON, IFLA_BOND_UPDELAY, IFLA_BOND_DOWNDELAY, + IFLA_BOND_USE_CARRIER, __IFLA_BOND_MAX, }; From 06151dbcf3f76edbe900138cde9e862f429918c9 Mon Sep 17 00:00:00 2001 From: "sfeldma@cumulusnetworks.com" Date: Thu, 12 Dec 2013 14:10:24 -0800 Subject: [PATCH 5/8] bonding: add arp_interval netlink support Add IFLA_BOND_ARP_INTERVAL to allow get/set of bonding parameter arp_interval via netlink. Signed-off-by: Scott Feldman Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/bonding/bond_netlink.c | 21 +++++++++- drivers/net/bonding/bond_options.c | 47 +++++++++++++++++++++++ drivers/net/bonding/bond_sysfs.c | 61 ++++++------------------------ drivers/net/bonding/bonding.h | 1 + include/uapi/linux/if_link.h | 1 + 5 files changed, 80 insertions(+), 51 deletions(-) diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index 7edf6399cea24..58e71235b75f4 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -28,6 +28,7 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = { [IFLA_BOND_UPDELAY] = { .type = NLA_U32 }, [IFLA_BOND_DOWNDELAY] = { .type = NLA_U32 }, [IFLA_BOND_USE_CARRIER] = { .type = NLA_U8 }, + [IFLA_BOND_ARP_INTERVAL] = { .type = NLA_U32 }, }; static int bond_validate(struct nlattr *tb[], struct nlattr *data[]) @@ -45,6 +46,7 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], struct nlattr *data[]) { struct bonding *bond = netdev_priv(bond_dev); + int miimon = 0; int err; if (!data) @@ -74,7 +76,7 @@ static int bond_changelink(struct net_device *bond_dev, return err; } if (data[IFLA_BOND_MIIMON]) { - int miimon = nla_get_u32(data[IFLA_BOND_MIIMON]); + miimon = nla_get_u32(data[IFLA_BOND_MIIMON]); err = bond_option_miimon_set(bond, miimon); if (err) @@ -101,6 +103,19 @@ static int bond_changelink(struct net_device *bond_dev, if (err) return err; } + if (data[IFLA_BOND_ARP_INTERVAL]) { + int arp_interval = nla_get_u32(data[IFLA_BOND_ARP_INTERVAL]); + + if (arp_interval && miimon) { + pr_err("%s: ARP monitoring cannot be used with MII monitoring.\n", + bond->dev->name); + return -EINVAL; + } + + err = bond_option_arp_interval_set(bond, arp_interval); + if (err) + return err; + } return 0; } @@ -124,6 +139,7 @@ static size_t bond_get_size(const struct net_device *bond_dev) nla_total_size(sizeof(u32)) + /* IFLA_BOND_UPDELAY */ nla_total_size(sizeof(u32)) + /* IFLA_BOND_DOWNDELAY */ nla_total_size(sizeof(u8)) + /* IFLA_BOND_USE_CARRIER */ + nla_total_size(sizeof(u32)) + /* IFLA_BOND_ARP_INTERVAL */ 0; } @@ -154,6 +170,9 @@ static int bond_fill_info(struct sk_buff *skb, if (nla_put_u8(skb, IFLA_BOND_USE_CARRIER, bond->params.use_carrier)) goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BOND_ARP_INTERVAL, bond->params.arp_interval)) + goto nla_put_failure; + return 0; nla_put_failure: diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index 6fc7bbf0b85f9..a84e729d02ef2 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -259,3 +259,50 @@ int bond_option_use_carrier_set(struct bonding *bond, int use_carrier) return 0; } + +int bond_option_arp_interval_set(struct bonding *bond, int arp_interval) +{ + if (arp_interval < 0) { + pr_err("%s: Invalid arp_interval value %d not in range 0-%d; rejected.\n", + bond->dev->name, arp_interval, INT_MAX); + return -EINVAL; + } + if (BOND_NO_USES_ARP(bond->params.mode)) { + pr_info("%s: ARP monitoring cannot be used with ALB/TLB/802.3ad. Only MII monitoring is supported on %s.\n", + bond->dev->name, bond->dev->name); + return -EINVAL; + } + pr_info("%s: Setting ARP monitoring interval to %d.\n", + bond->dev->name, arp_interval); + bond->params.arp_interval = arp_interval; + if (arp_interval) { + if (bond->params.miimon) { + pr_info("%s: ARP monitoring cannot be used with MII monitoring. %s Disabling MII monitoring.\n", + bond->dev->name, bond->dev->name); + bond->params.miimon = 0; + } + if (!bond->params.arp_targets[0]) + pr_info("%s: ARP monitoring has been set up, but no ARP targets have been specified.\n", + bond->dev->name); + } + if (bond->dev->flags & IFF_UP) { + /* If the interface is up, we may need to fire off + * the ARP timer. If the interface is down, the + * timer will get fired off when the open function + * is called. + */ + if (!arp_interval) { + if (bond->params.arp_validate) + bond->recv_probe = NULL; + cancel_delayed_work_sync(&bond->arp_work); + } else { + /* arp_validate can be set only in active-backup mode */ + if (bond->params.arp_validate) + bond->recv_probe = bond_arp_rcv; + cancel_delayed_work_sync(&bond->mii_work); + queue_delayed_work(bond->wq, &bond->arp_work, 0); + } + } + + return 0; +} diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 114760af9a6db..12128bfa88cea 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -506,60 +506,21 @@ static ssize_t bonding_store_arp_interval(struct device *d, const char *buf, size_t count) { struct bonding *bond = to_bond(d); - int new_value, ret = count; + int new_value, ret; - if (!rtnl_trylock()) - return restart_syscall(); if (sscanf(buf, "%d", &new_value) != 1) { pr_err("%s: no arp_interval value specified.\n", - bond->dev->name); - ret = -EINVAL; - goto out; - } - if (new_value < 0) { - pr_err("%s: Invalid arp_interval value %d not in range 0-%d; rejected.\n", - bond->dev->name, new_value, INT_MAX); - ret = -EINVAL; - goto out; - } - if (BOND_NO_USES_ARP(bond->params.mode)) { - pr_info("%s: ARP monitoring cannot be used with ALB/TLB/802.3ad. Only MII monitoring is supported on %s.\n", - bond->dev->name, bond->dev->name); - ret = -EINVAL; - goto out; - } - pr_info("%s: Setting ARP monitoring interval to %d.\n", - bond->dev->name, new_value); - bond->params.arp_interval = new_value; - if (new_value) { - if (bond->params.miimon) { - pr_info("%s: ARP monitoring cannot be used with MII monitoring. %s Disabling MII monitoring.\n", - bond->dev->name, bond->dev->name); - bond->params.miimon = 0; - } - if (!bond->params.arp_targets[0]) - pr_info("%s: ARP monitoring has been set up, but no ARP targets have been specified.\n", - bond->dev->name); - } - if (bond->dev->flags & IFF_UP) { - /* If the interface is up, we may need to fire off - * the ARP timer. If the interface is down, the - * timer will get fired off when the open function - * is called. - */ - if (!new_value) { - if (bond->params.arp_validate) - bond->recv_probe = NULL; - cancel_delayed_work_sync(&bond->arp_work); - } else { - /* arp_validate can be set only in active-backup mode */ - if (bond->params.arp_validate) - bond->recv_probe = bond_arp_rcv; - cancel_delayed_work_sync(&bond->mii_work); - queue_delayed_work(bond->wq, &bond->arp_work, 0); - } + bond->dev->name); + return -EINVAL; } -out: + + if (!rtnl_trylock()) + return restart_syscall(); + + ret = bond_option_arp_interval_set(bond, new_value); + if (!ret) + ret = count; + rtnl_unlock(); return ret; } diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index df159da8db309..44df2738577d8 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -443,6 +443,7 @@ int bond_option_miimon_set(struct bonding *bond, int miimon); int bond_option_updelay_set(struct bonding *bond, int updelay); int bond_option_downdelay_set(struct bonding *bond, int downdelay); int bond_option_use_carrier_set(struct bonding *bond, int use_carrier); +int bond_option_arp_interval_set(struct bonding *bond, int arp_interval); struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond); struct net_device *bond_option_active_slave_get(struct bonding *bond); diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 77c41bda36a42..c73d878afd587 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -335,6 +335,7 @@ enum { IFLA_BOND_UPDELAY, IFLA_BOND_DOWNDELAY, IFLA_BOND_USE_CARRIER, + IFLA_BOND_ARP_INTERVAL, __IFLA_BOND_MAX, }; From 7f28fa10e21376a10d3b9faad5836869465cc376 Mon Sep 17 00:00:00 2001 From: "sfeldma@cumulusnetworks.com" Date: Thu, 12 Dec 2013 14:10:31 -0800 Subject: [PATCH 6/8] bonding: add arp_ip_target netlink support Add IFLA_BOND_ARP_IP_TARGET to allow get/set of bonding parameter arp_ip_target via netlink. Signed-off-by: Scott Feldman Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/bonding/bond_netlink.c | 36 ++++++++ drivers/net/bonding/bond_options.c | 130 +++++++++++++++++++++++++++++ drivers/net/bonding/bond_sysfs.c | 84 ++++--------------- drivers/net/bonding/bonding.h | 4 + include/uapi/linux/if_link.h | 1 + 5 files changed, 187 insertions(+), 68 deletions(-) diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index 58e71235b75f4..6d30e5db9e3cd 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -29,6 +29,7 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = { [IFLA_BOND_DOWNDELAY] = { .type = NLA_U32 }, [IFLA_BOND_USE_CARRIER] = { .type = NLA_U8 }, [IFLA_BOND_ARP_INTERVAL] = { .type = NLA_U32 }, + [IFLA_BOND_ARP_IP_TARGET] = { .type = NLA_NESTED }, }; static int bond_validate(struct nlattr *tb[], struct nlattr *data[]) @@ -116,6 +117,20 @@ static int bond_changelink(struct net_device *bond_dev, if (err) return err; } + if (data[IFLA_BOND_ARP_IP_TARGET]) { + __be32 targets[BOND_MAX_ARP_TARGETS] = { 0, }; + struct nlattr *attr; + int i = 0, rem; + + nla_for_each_nested(attr, data[IFLA_BOND_ARP_IP_TARGET], rem) { + __be32 target = nla_get_u32(attr); + targets[i++] = target; + } + + err = bond_option_arp_ip_targets_set(bond, targets, i); + if (err) + return err; + } return 0; } @@ -140,6 +155,8 @@ static size_t bond_get_size(const struct net_device *bond_dev) nla_total_size(sizeof(u32)) + /* IFLA_BOND_DOWNDELAY */ nla_total_size(sizeof(u8)) + /* IFLA_BOND_USE_CARRIER */ nla_total_size(sizeof(u32)) + /* IFLA_BOND_ARP_INTERVAL */ + /* IFLA_BOND_ARP_IP_TARGET */ + nla_total_size(sizeof(u32)) * BOND_MAX_ARP_TARGETS + 0; } @@ -148,6 +165,8 @@ static int bond_fill_info(struct sk_buff *skb, { struct bonding *bond = netdev_priv(bond_dev); struct net_device *slave_dev = bond_option_active_slave_get(bond); + struct nlattr *targets; + int i, targets_added; if (nla_put_u8(skb, IFLA_BOND_MODE, bond->params.mode)) goto nla_put_failure; @@ -173,6 +192,23 @@ static int bond_fill_info(struct sk_buff *skb, if (nla_put_u32(skb, IFLA_BOND_ARP_INTERVAL, bond->params.arp_interval)) goto nla_put_failure; + targets = nla_nest_start(skb, IFLA_BOND_ARP_IP_TARGET); + if (!targets) + goto nla_put_failure; + + targets_added = 0; + for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) { + if (bond->params.arp_targets[i]) { + nla_put_u32(skb, i, bond->params.arp_targets[i]); + targets_added = 1; + } + } + + if (targets_added) + nla_nest_end(skb, targets); + else + nla_nest_cancel(skb, targets); + return 0; nla_put_failure: diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index a84e729d02ef2..f8c2e4f170662 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -306,3 +306,133 @@ int bond_option_arp_interval_set(struct bonding *bond, int arp_interval) return 0; } + +static void _bond_options_arp_ip_target_set(struct bonding *bond, int slot, + __be32 target, + unsigned long last_rx) +{ + __be32 *targets = bond->params.arp_targets; + struct list_head *iter; + struct slave *slave; + + if (slot >= 0 && slot < BOND_MAX_ARP_TARGETS) { + bond_for_each_slave(bond, slave, iter) + slave->target_last_arp_rx[slot] = last_rx; + targets[slot] = target; + } +} + +static int _bond_option_arp_ip_target_add(struct bonding *bond, __be32 target) +{ + __be32 *targets = bond->params.arp_targets; + int ind; + + if (IS_IP_TARGET_UNUSABLE_ADDRESS(target)) { + pr_err("%s: invalid ARP target %pI4 specified for addition\n", + bond->dev->name, &target); + return -EINVAL; + } + + if (bond_get_targets_ip(targets, target) != -1) { /* dup */ + pr_err("%s: ARP target %pI4 is already present\n", + bond->dev->name, &target); + return -EINVAL; + } + + ind = bond_get_targets_ip(targets, 0); /* first free slot */ + if (ind == -1) { + pr_err("%s: ARP target table is full!\n", + bond->dev->name); + return -EINVAL; + } + + pr_info("%s: adding ARP target %pI4.\n", bond->dev->name, &target); + + _bond_options_arp_ip_target_set(bond, ind, target, jiffies); + + return 0; +} + +int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target) +{ + int ret; + + /* not to race with bond_arp_rcv */ + write_lock_bh(&bond->lock); + ret = _bond_option_arp_ip_target_add(bond, target); + write_unlock_bh(&bond->lock); + + return ret; +} + +int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target) +{ + __be32 *targets = bond->params.arp_targets; + struct list_head *iter; + struct slave *slave; + unsigned long *targets_rx; + int ind, i; + + if (IS_IP_TARGET_UNUSABLE_ADDRESS(target)) { + pr_err("%s: invalid ARP target %pI4 specified for removal\n", + bond->dev->name, &target); + return -EINVAL; + } + + ind = bond_get_targets_ip(targets, target); + if (ind == -1) { + pr_err("%s: unable to remove nonexistent ARP target %pI4.\n", + bond->dev->name, &target); + return -EINVAL; + } + + if (ind == 0 && !targets[1] && bond->params.arp_interval) + pr_warn("%s: removing last arp target with arp_interval on\n", + bond->dev->name); + + pr_info("%s: removing ARP target %pI4.\n", bond->dev->name, + &target); + + /* not to race with bond_arp_rcv */ + write_lock_bh(&bond->lock); + + bond_for_each_slave(bond, slave, iter) { + targets_rx = slave->target_last_arp_rx; + for (i = ind; (i < BOND_MAX_ARP_TARGETS-1) && targets[i+1]; i++) + targets_rx[i] = targets_rx[i+1]; + targets_rx[i] = 0; + } + for (i = ind; (i < BOND_MAX_ARP_TARGETS-1) && targets[i+1]; i++) + targets[i] = targets[i+1]; + targets[i] = 0; + + write_unlock_bh(&bond->lock); + + return 0; +} + +int bond_option_arp_ip_targets_set(struct bonding *bond, __be32 *targets, + int count) +{ + int i, ret = 0; + + /* not to race with bond_arp_rcv */ + write_lock_bh(&bond->lock); + + /* clear table */ + for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) + _bond_options_arp_ip_target_set(bond, i, 0, 0); + + if (count == 0 && bond->params.arp_interval) + pr_warn("%s: removing last arp target with arp_interval on\n", + bond->dev->name); + + for (i = 0; i < count; i++) { + ret = _bond_option_arp_ip_target_add(bond, targets[i]); + if (ret) + break; + } + + write_unlock_bh(&bond->lock); + return ret; +} diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 12128bfa88cea..a443bbd0fe86b 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -552,81 +552,29 @@ static ssize_t bonding_store_arp_targets(struct device *d, const char *buf, size_t count) { struct bonding *bond = to_bond(d); - struct list_head *iter; - struct slave *slave; - __be32 newtarget, *targets; - unsigned long *targets_rx; - int ind, i, j, ret = -EINVAL; + __be32 target; + int ret = -EPERM; - if (!rtnl_trylock()) - return restart_syscall(); - - targets = bond->params.arp_targets; - if (!in4_pton(buf + 1, -1, (u8 *)&newtarget, -1, NULL) || - IS_IP_TARGET_UNUSABLE_ADDRESS(newtarget)) { - pr_err("%s: invalid ARP target %pI4 specified for addition\n", - bond->dev->name, &newtarget); - goto out; + if (!in4_pton(buf + 1, -1, (u8 *)&target, -1, NULL)) { + pr_err("%s: invalid ARP target %pI4 specified\n", + bond->dev->name, &target); + return -EPERM; } - /* look for adds */ - if (buf[0] == '+') { - if (bond_get_targets_ip(targets, newtarget) != -1) { /* dup */ - pr_err("%s: ARP target %pI4 is already present\n", - bond->dev->name, &newtarget); - goto out; - } - - ind = bond_get_targets_ip(targets, 0); /* first free slot */ - if (ind == -1) { - pr_err("%s: ARP target table is full!\n", - bond->dev->name); - goto out; - } - - pr_info("%s: adding ARP target %pI4.\n", bond->dev->name, - &newtarget); - /* not to race with bond_arp_rcv */ - write_lock_bh(&bond->lock); - bond_for_each_slave(bond, slave, iter) - slave->target_last_arp_rx[ind] = jiffies; - targets[ind] = newtarget; - write_unlock_bh(&bond->lock); - } else if (buf[0] == '-') { - ind = bond_get_targets_ip(targets, newtarget); - if (ind == -1) { - pr_err("%s: unable to remove nonexistent ARP target %pI4.\n", - bond->dev->name, &newtarget); - goto out; - } - if (ind == 0 && !targets[1] && bond->params.arp_interval) - pr_warn("%s: removing last arp target with arp_interval on\n", - bond->dev->name); - - pr_info("%s: removing ARP target %pI4.\n", bond->dev->name, - &newtarget); + if (!rtnl_trylock()) + return restart_syscall(); - write_lock_bh(&bond->lock); - bond_for_each_slave(bond, slave, iter) { - targets_rx = slave->target_last_arp_rx; - j = ind; - for (; (j < BOND_MAX_ARP_TARGETS-1) && targets[j+1]; j++) - targets_rx[j] = targets_rx[j+1]; - targets_rx[j] = 0; - } - for (i = ind; (i < BOND_MAX_ARP_TARGETS-1) && targets[i+1]; i++) - targets[i] = targets[i+1]; - targets[i] = 0; - write_unlock_bh(&bond->lock); - } else { + if (buf[0] == '+') + ret = bond_option_arp_ip_target_add(bond, target); + else if (buf[0] == '-') + ret = bond_option_arp_ip_target_rem(bond, target); + else pr_err("no command found in arp_ip_targets file for bond %s. Use + or -.\n", bond->dev->name); - ret = -EPERM; - goto out; - } - ret = count; -out: + if (!ret) + ret = count; + rtnl_unlock(); return ret; } diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 44df2738577d8..dcdc8095c169a 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -444,6 +444,10 @@ int bond_option_updelay_set(struct bonding *bond, int updelay); int bond_option_downdelay_set(struct bonding *bond, int downdelay); int bond_option_use_carrier_set(struct bonding *bond, int use_carrier); int bond_option_arp_interval_set(struct bonding *bond, int arp_interval); +int bond_option_arp_ip_targets_set(struct bonding *bond, __be32 *targets, + int count); +int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target); +int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target); struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond); struct net_device *bond_option_active_slave_get(struct bonding *bond); diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index c73d878afd587..5b0c444692790 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -336,6 +336,7 @@ enum { IFLA_BOND_DOWNDELAY, IFLA_BOND_USE_CARRIER, IFLA_BOND_ARP_INTERVAL, + IFLA_BOND_ARP_IP_TARGET, __IFLA_BOND_MAX, }; From 29c4948293bfc426e52a921f4259eb3676961e81 Mon Sep 17 00:00:00 2001 From: "sfeldma@cumulusnetworks.com" Date: Thu, 12 Dec 2013 14:10:38 -0800 Subject: [PATCH 7/8] bonding: add arp_validate netlink support Add IFLA_BOND_ARP_VALIDATE to allow get/set of bonding parameter arp_validate via netlink. Signed-off-by: Scott Feldman Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/bonding/bond_netlink.c | 18 ++++++++++++++++++ drivers/net/bonding/bond_options.c | 22 ++++++++++++++++++++++ drivers/net/bonding/bond_sysfs.c | 30 ++++++++---------------------- drivers/net/bonding/bonding.h | 1 + include/uapi/linux/if_link.h | 1 + 5 files changed, 50 insertions(+), 22 deletions(-) diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index 6d30e5db9e3cd..8588cb91caa99 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -30,6 +30,7 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = { [IFLA_BOND_USE_CARRIER] = { .type = NLA_U8 }, [IFLA_BOND_ARP_INTERVAL] = { .type = NLA_U32 }, [IFLA_BOND_ARP_IP_TARGET] = { .type = NLA_NESTED }, + [IFLA_BOND_ARP_VALIDATE] = { .type = NLA_U32 }, }; static int bond_validate(struct nlattr *tb[], struct nlattr *data[]) @@ -131,6 +132,19 @@ static int bond_changelink(struct net_device *bond_dev, if (err) return err; } + if (data[IFLA_BOND_ARP_VALIDATE]) { + int arp_validate = nla_get_u32(data[IFLA_BOND_ARP_VALIDATE]); + + if (arp_validate && miimon) { + pr_err("%s: ARP validating cannot be used with MII monitoring.\n", + bond->dev->name); + return -EINVAL; + } + + err = bond_option_arp_validate_set(bond, arp_validate); + if (err) + return err; + } return 0; } @@ -157,6 +171,7 @@ static size_t bond_get_size(const struct net_device *bond_dev) nla_total_size(sizeof(u32)) + /* IFLA_BOND_ARP_INTERVAL */ /* IFLA_BOND_ARP_IP_TARGET */ nla_total_size(sizeof(u32)) * BOND_MAX_ARP_TARGETS + + nla_total_size(sizeof(u32)) + /* IFLA_BOND_ARP_VALIDATE */ 0; } @@ -209,6 +224,9 @@ static int bond_fill_info(struct sk_buff *skb, else nla_nest_cancel(skb, targets); + if (nla_put_u32(skb, IFLA_BOND_ARP_VALIDATE, bond->params.arp_validate)) + goto nla_put_failure; + return 0; nla_put_failure: diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index f8c2e4f170662..698079e94e744 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -436,3 +436,25 @@ int bond_option_arp_ip_targets_set(struct bonding *bond, __be32 *targets, write_unlock_bh(&bond->lock); return ret; } + +int bond_option_arp_validate_set(struct bonding *bond, int arp_validate) +{ + if (bond->params.mode != BOND_MODE_ACTIVEBACKUP) { + pr_err("%s: arp_validate only supported in active-backup mode.\n", + bond->dev->name); + return -EINVAL; + } + pr_info("%s: setting arp_validate to %s (%d).\n", + bond->dev->name, arp_validate_tbl[arp_validate].modename, + arp_validate); + + if (bond->dev->flags & IFF_UP) { + if (!arp_validate) + bond->recv_probe = NULL; + else if (bond->params.arp_interval) + bond->recv_probe = bond_arp_rcv; + } + bond->params.arp_validate = arp_validate; + + return 0; +} diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index a443bbd0fe86b..bda00a01393ad 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -358,35 +358,21 @@ static ssize_t bonding_store_arp_validate(struct device *d, const char *buf, size_t count) { struct bonding *bond = to_bond(d); - int new_value, ret = count; + int new_value, ret; - if (!rtnl_trylock()) - return restart_syscall(); new_value = bond_parse_parm(buf, arp_validate_tbl); if (new_value < 0) { pr_err("%s: Ignoring invalid arp_validate value %s\n", bond->dev->name, buf); - ret = -EINVAL; - goto out; - } - if (bond->params.mode != BOND_MODE_ACTIVEBACKUP) { - pr_err("%s: arp_validate only supported in active-backup mode.\n", - bond->dev->name); - ret = -EINVAL; - goto out; + return -EINVAL; } - pr_info("%s: setting arp_validate to %s (%d).\n", - bond->dev->name, arp_validate_tbl[new_value].modename, - new_value); + if (!rtnl_trylock()) + return restart_syscall(); + + ret = bond_option_arp_validate_set(bond, new_value); + if (!ret) + ret = count; - if (bond->dev->flags & IFF_UP) { - if (!new_value) - bond->recv_probe = NULL; - else if (bond->params.arp_interval) - bond->recv_probe = bond_arp_rcv; - } - bond->params.arp_validate = new_value; -out: rtnl_unlock(); return ret; diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index dcdc8095c169a..cef10adac6e65 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -448,6 +448,7 @@ int bond_option_arp_ip_targets_set(struct bonding *bond, __be32 *targets, int count); int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target); int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target); +int bond_option_arp_validate_set(struct bonding *bond, int arp_validate); struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond); struct net_device *bond_option_active_slave_get(struct bonding *bond); diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 5b0c444692790..3ba16fa9ad6c3 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -337,6 +337,7 @@ enum { IFLA_BOND_USE_CARRIER, IFLA_BOND_ARP_INTERVAL, IFLA_BOND_ARP_IP_TARGET, + IFLA_BOND_ARP_VALIDATE, __IFLA_BOND_MAX, }; From d5c842544342fc3f13774ffc5581d4dd3975059b Mon Sep 17 00:00:00 2001 From: "sfeldma@cumulusnetworks.com" Date: Thu, 12 Dec 2013 14:10:45 -0800 Subject: [PATCH 8/8] bonding: add arp_all_targets netlink support Add IFLA_BOND_ARP_ALL_TARGETS to allow get/set of bonding parameter arp_all_targets via netlink. Signed-off-by: Scott Feldman Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/bonding/bond_netlink.c | 14 ++++++++++++++ drivers/net/bonding/bond_options.c | 11 +++++++++++ drivers/net/bonding/bond_sysfs.c | 16 ++++++++++------ drivers/net/bonding/bonding.h | 1 + include/uapi/linux/if_link.h | 1 + 5 files changed, 37 insertions(+), 6 deletions(-) diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index 8588cb91caa99..d7d84db9eed7b 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -31,6 +31,7 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = { [IFLA_BOND_ARP_INTERVAL] = { .type = NLA_U32 }, [IFLA_BOND_ARP_IP_TARGET] = { .type = NLA_NESTED }, [IFLA_BOND_ARP_VALIDATE] = { .type = NLA_U32 }, + [IFLA_BOND_ARP_ALL_TARGETS] = { .type = NLA_U32 }, }; static int bond_validate(struct nlattr *tb[], struct nlattr *data[]) @@ -145,6 +146,14 @@ static int bond_changelink(struct net_device *bond_dev, if (err) return err; } + if (data[IFLA_BOND_ARP_ALL_TARGETS]) { + int arp_all_targets = + nla_get_u32(data[IFLA_BOND_ARP_ALL_TARGETS]); + + err = bond_option_arp_all_targets_set(bond, arp_all_targets); + if (err) + return err; + } return 0; } @@ -172,6 +181,7 @@ static size_t bond_get_size(const struct net_device *bond_dev) /* IFLA_BOND_ARP_IP_TARGET */ nla_total_size(sizeof(u32)) * BOND_MAX_ARP_TARGETS + nla_total_size(sizeof(u32)) + /* IFLA_BOND_ARP_VALIDATE */ + nla_total_size(sizeof(u32)) + /* IFLA_BOND_ARP_ALL_TARGETS */ 0; } @@ -227,6 +237,10 @@ static int bond_fill_info(struct sk_buff *skb, if (nla_put_u32(skb, IFLA_BOND_ARP_VALIDATE, bond->params.arp_validate)) goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BOND_ARP_ALL_TARGETS, + bond->params.arp_all_targets)) + goto nla_put_failure; + return 0; nla_put_failure: diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index 698079e94e744..dfef673d53d10 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -458,3 +458,14 @@ int bond_option_arp_validate_set(struct bonding *bond, int arp_validate) return 0; } + +int bond_option_arp_all_targets_set(struct bonding *bond, int arp_all_targets) +{ + pr_info("%s: setting arp_all_targets to %s (%d).\n", + bond->dev->name, arp_all_targets_tbl[arp_all_targets].modename, + arp_all_targets); + + bond->params.arp_all_targets = arp_all_targets; + + return 0; +} diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index bda00a01393ad..dad9bea95122d 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -399,7 +399,7 @@ static ssize_t bonding_store_arp_all_targets(struct device *d, const char *buf, size_t count) { struct bonding *bond = to_bond(d); - int new_value; + int new_value, ret; new_value = bond_parse_parm(buf, arp_all_targets_tbl); if (new_value < 0) { @@ -407,13 +407,17 @@ static ssize_t bonding_store_arp_all_targets(struct device *d, bond->dev->name, buf); return -EINVAL; } - pr_info("%s: setting arp_all_targets to %s (%d).\n", - bond->dev->name, arp_all_targets_tbl[new_value].modename, - new_value); - bond->params.arp_all_targets = new_value; + if (!rtnl_trylock()) + return restart_syscall(); - return count; + ret = bond_option_arp_all_targets_set(bond, new_value); + if (!ret) + ret = count; + + rtnl_unlock(); + + return ret; } static DEVICE_ATTR(arp_all_targets, S_IRUGO | S_IWUSR, diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index cef10adac6e65..8283cbdec50aa 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -449,6 +449,7 @@ int bond_option_arp_ip_targets_set(struct bonding *bond, __be32 *targets, int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target); int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target); int bond_option_arp_validate_set(struct bonding *bond, int arp_validate); +int bond_option_arp_all_targets_set(struct bonding *bond, int arp_all_targets); struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond); struct net_device *bond_option_active_slave_get(struct bonding *bond); diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 3ba16fa9ad6c3..a897b7e22541d 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -338,6 +338,7 @@ enum { IFLA_BOND_ARP_INTERVAL, IFLA_BOND_ARP_IP_TARGET, IFLA_BOND_ARP_VALIDATE, + IFLA_BOND_ARP_ALL_TARGETS, __IFLA_BOND_MAX, };