summaryrefslogtreecommitdiff
path: root/net/core/rtnetlink.c
diff options
context:
space:
mode:
authorsfeldma@cumulusnetworks.com <sfeldma@cumulusnetworks.com>2014-01-16 22:57:56 -0800
committerDavid S. Miller <davem@davemloft.net>2014-01-17 18:51:58 -0800
commit1d3ee88ae0d605629bf369ab0b868dae8ca62a48 (patch)
tree7d547bb8ba12b9417a8f0055a08f1026d6392cf2 /net/core/rtnetlink.c
parent07699f9a7c8d1002e07011d5aa382cd63241eea8 (diff)
bonding: add netlink attributes to slave link dev
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 <sfeldma@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core/rtnetlink.c')
-rw-r--r--net/core/rtnetlink.c54
1 files changed, 54 insertions, 0 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index e6e7d582f901..4f85de7aca33 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -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)
{
@@ -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 */
}
@@ -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)
@@ -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;