Skip to content

Commit

Permalink
bonding: add netlink attributes to slave link dev
Browse files Browse the repository at this point in the history
If link is IFF_SLAVE, extend link dev netlink attributes to include
slave attributes with new IFLA_SLAVE nest.  Add netlink notification
(RTM_NEWLINK) when slave status changes from backup to active, or
visa-versa.

Adds new ndo_get_slave op to net_device_ops to fill skb with IFLA_SLAVE
attributes.  Currently only used by bonding driver, but could be
used by other aggregating devices with slaves.

Signed-off-by: Scott Feldman <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
[email protected] authored and davem330 committed Jan 18, 2014
1 parent 07699f9 commit 1d3ee88
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 2 deletions.
1 change: 1 addition & 0 deletions drivers/net/bonding/bond_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -3883,6 +3883,7 @@ static const struct net_device_ops bond_netdev_ops = {
#endif
.ndo_add_slave = bond_enslave,
.ndo_del_slave = bond_release,
.ndo_get_slave = bond_get_slave,
.ndo_fix_features = bond_fix_features,
};

Expand Down
36 changes: 36 additions & 0 deletions drivers/net/bonding/bond_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,42 @@
#include <linux/reciprocal_div.h>
#include "bonding.h"

int bond_get_slave(struct net_device *slave_dev, struct sk_buff *skb)
{
struct slave *slave = bond_slave_get_rtnl(slave_dev);
const struct aggregator *agg;

if (nla_put_u8(skb, IFLA_SLAVE_STATE, bond_slave_state(slave)))
goto nla_put_failure;

if (nla_put_u8(skb, IFLA_SLAVE_MII_STATUS, slave->link))
goto nla_put_failure;

if (nla_put_u32(skb, IFLA_SLAVE_LINK_FAILURE_COUNT,
slave->link_failure_count))
goto nla_put_failure;

if (nla_put(skb, IFLA_SLAVE_PERM_HWADDR,
slave_dev->addr_len, slave->perm_hwaddr))
goto nla_put_failure;

if (nla_put_u16(skb, IFLA_SLAVE_QUEUE_ID, slave->queue_id))
goto nla_put_failure;

if (slave->bond->params.mode == BOND_MODE_8023AD) {
agg = SLAVE_AD_INFO(slave).port.aggregator;
if (agg)
if (nla_put_u16(skb, IFLA_SLAVE_AD_AGGREGATOR_ID,
agg->aggregator_identifier))
goto nla_put_failure;
}

return 0;

nla_put_failure:
return -EMSGSIZE;
}

static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = {
[IFLA_BOND_MODE] = { .type = NLA_U8 },
[IFLA_BOND_ACTIVE_SLAVE] = { .type = NLA_U32 },
Expand Down
11 changes: 9 additions & 2 deletions drivers/net/bonding/bonding.h
Original file line number Diff line number Diff line change
Expand Up @@ -285,12 +285,18 @@ static inline bool bond_is_lb(const struct bonding *bond)

static inline void bond_set_active_slave(struct slave *slave)
{
slave->backup = 0;
if (slave->backup) {
slave->backup = 0;
rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_KERNEL);
}
}

static inline void bond_set_backup_slave(struct slave *slave)
{
slave->backup = 1;
if (!slave->backup) {
slave->backup = 1;
rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_KERNEL);
}
}

static inline int bond_slave_state(struct slave *slave)
Expand Down Expand Up @@ -426,6 +432,7 @@ int bond_sysfs_slave_add(struct slave *slave);
void bond_sysfs_slave_del(struct slave *slave);
int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev);
int bond_release(struct net_device *bond_dev, struct net_device *slave_dev);
int bond_get_slave(struct net_device *slave_dev, struct sk_buff *skb);
int bond_xmit_hash(struct bonding *bond, struct sk_buff *skb, int count);
int bond_parse_parm(const char *mode_arg, const struct bond_parm_tbl *tbl);
int bond_parm_tbl_lookup(int mode, const struct bond_parm_tbl *tbl);
Expand Down
5 changes: 5 additions & 0 deletions include/linux/netdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -921,6 +921,9 @@ struct netdev_phys_port_id {
* int (*ndo_del_slave)(struct net_device *dev, struct net_device *slave_dev);
* Called to release previously enslaved netdev.
*
* int (*ndo_get_slave)(struct net_device *slave_dev, struct sk_buff *skb);
* Called to fill netlink skb with slave info.
*
* Feature/offload setting functions.
* netdev_features_t (*ndo_fix_features)(struct net_device *dev,
* netdev_features_t features);
Expand Down Expand Up @@ -1093,6 +1096,8 @@ struct net_device_ops {
struct net_device *slave_dev);
int (*ndo_del_slave)(struct net_device *dev,
struct net_device *slave_dev);
int (*ndo_get_slave)(struct net_device *slave_dev,
struct sk_buff *skb);
netdev_features_t (*ndo_fix_features)(struct net_device *dev,
netdev_features_t features);
int (*ndo_set_features)(struct net_device *dev,
Expand Down
13 changes: 13 additions & 0 deletions include/uapi/linux/if_link.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ enum {
IFLA_NUM_RX_QUEUES,
IFLA_CARRIER,
IFLA_PHYS_PORT_ID,
IFLA_SLAVE,
__IFLA_MAX
};

Expand Down Expand Up @@ -368,6 +369,18 @@ enum {

#define IFLA_BOND_AD_INFO_MAX (__IFLA_BOND_AD_INFO_MAX - 1)

enum {
IFLA_SLAVE_STATE,
IFLA_SLAVE_MII_STATUS,
IFLA_SLAVE_LINK_FAILURE_COUNT,
IFLA_SLAVE_PERM_HWADDR,
IFLA_SLAVE_QUEUE_ID,
IFLA_SLAVE_AD_AGGREGATOR_ID,
__IFLA_SLAVE_MAX,
};

#define IFLA_SLAVE_MAX (__IFLA_SLAVE_MAX - 1)

/* SR-IOV virtual function management section */

enum {
Expand Down
54 changes: 54 additions & 0 deletions net/core/rtnetlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,28 @@ static size_t rtnl_port_size(const struct net_device *dev)
return port_self_size;
}

static size_t rtnl_bond_slave_size(const struct net_device *dev)
{
struct net_device *bond;
size_t slave_size =
nla_total_size(sizeof(struct nlattr)) + /* IFLA_SLAVE */
nla_total_size(1) + /* IFLA_SLAVE_STATE */
nla_total_size(1) + /* IFLA_SLAVE_MII_STATUS */
nla_total_size(4) + /* IFLA_SLAVE_LINK_FAILURE_COUNT */
nla_total_size(MAX_ADDR_LEN) + /* IFLA_SLAVE_PERM_HWADDR */
nla_total_size(2) + /* IFLA_SLAVE_QUEUE_ID */
nla_total_size(2) + /* IFLA_SLAVE_AD_AGGREGATOR_ID */
0;

if (netif_is_bond_slave((struct net_device *)dev)) {
bond = netdev_master_upper_dev_get((struct net_device *)dev);
if (bond && bond->netdev_ops->ndo_get_slave)
return slave_size;
}

return 0;
}

static noinline size_t if_nlmsg_size(const struct net_device *dev,
u32 ext_filter_mask)
{
Expand Down Expand Up @@ -750,6 +772,7 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev,
+ rtnl_port_size(dev) /* IFLA_VF_PORTS + IFLA_PORT_SELF */
+ rtnl_link_get_size(dev) /* IFLA_LINKINFO */
+ rtnl_link_get_af_size(dev) /* IFLA_AF_SPEC */
+ rtnl_bond_slave_size(dev) /* IFLA_SLAVE */
+ nla_total_size(MAX_PHYS_PORT_ID_LEN); /* IFLA_PHYS_PORT_ID */
}

Expand Down Expand Up @@ -847,6 +870,34 @@ static int rtnl_phys_port_id_fill(struct sk_buff *skb, struct net_device *dev)
return 0;
}

static size_t rtnl_bond_slave_fill(struct sk_buff *skb, struct net_device *dev)
{
struct net_device *bond;
struct nlattr *nest;
int err;

if (!netif_is_bond_slave(dev))
return 0;

bond = netdev_master_upper_dev_get(dev);
if (!bond || !bond->netdev_ops->ndo_get_slave)
return 0;

nest = nla_nest_start(skb, IFLA_SLAVE);
if (!nest)
return -EMSGSIZE;

err = bond->netdev_ops->ndo_get_slave(dev, skb);
if (err) {
nla_nest_cancel(skb, nest);
return (err == -EMSGSIZE) ? err : 0;
}

nla_nest_end(skb, nest);

return 0;
}

static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
int type, u32 pid, u32 seq, u32 change,
unsigned int flags, u32 ext_filter_mask)
Expand Down Expand Up @@ -1001,6 +1052,9 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
if (rtnl_port_fill(skb, dev))
goto nla_put_failure;

if (rtnl_bond_slave_fill(skb, dev))
goto nla_put_failure;

if (dev->rtnl_link_ops) {
if (rtnl_link_fill(skb, dev) < 0)
goto nla_put_failure;
Expand Down

0 comments on commit 1d3ee88

Please sign in to comment.