net-sysfs: expose number of carrier on/off changes
[deliverable/linux.git] / net / core / rtnetlink.c
index 120eecc0f5a471f0157894f48ee33f1d1f6a9af5..d4ff41739b0f23fcb572905dd34288cb1d8ebd49 100644 (file)
@@ -822,6 +822,7 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev,
               + nla_total_size(4) /* IFLA_NUM_RX_QUEUES */
               + nla_total_size(1) /* IFLA_OPERSTATE */
               + nla_total_size(1) /* IFLA_LINKMODE */
+              + nla_total_size(4) /* IFLA_CARRIER_CHANGES */
               + nla_total_size(ext_filter_mask
                                & RTEXT_FILTER_VF ? 4 : 0) /* IFLA_NUM_VF */
               + rtnl_vfinfo_size(dev, ext_filter_mask) /* IFLA_VFINFO_LIST */
@@ -970,7 +971,9 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
            (dev->qdisc &&
             nla_put_string(skb, IFLA_QDISC, dev->qdisc->ops->id)) ||
            (dev->ifalias &&
-            nla_put_string(skb, IFLA_IFALIAS, dev->ifalias)))
+            nla_put_string(skb, IFLA_IFALIAS, dev->ifalias)) ||
+           nla_put_u32(skb, IFLA_CARRIER_CHANGES,
+                       atomic_read(&dev->carrier_changes)))
                goto nla_put_failure;
 
        if (1) {
@@ -1121,56 +1124,7 @@ nla_put_failure:
        return -EMSGSIZE;
 }
 
-static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
-{
-       struct net *net = sock_net(skb->sk);
-       int h, s_h;
-       int idx = 0, s_idx;
-       struct net_device *dev;
-       struct hlist_head *head;
-       struct nlattr *tb[IFLA_MAX+1];
-       u32 ext_filter_mask = 0;
-
-       s_h = cb->args[0];
-       s_idx = cb->args[1];
-
-       rcu_read_lock();
-       cb->seq = net->dev_base_seq;
-
-       if (nlmsg_parse(cb->nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX,
-                       ifla_policy) >= 0) {
-
-               if (tb[IFLA_EXT_MASK])
-                       ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);
-       }
-
-       for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
-               idx = 0;
-               head = &net->dev_index_head[h];
-               hlist_for_each_entry_rcu(dev, head, index_hlist) {
-                       if (idx < s_idx)
-                               goto cont;
-                       if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK,
-                                            NETLINK_CB(cb->skb).portid,
-                                            cb->nlh->nlmsg_seq, 0,
-                                            NLM_F_MULTI,
-                                            ext_filter_mask) <= 0)
-                               goto out;
-
-                       nl_dump_check_consistent(cb, nlmsg_hdr(skb));
-cont:
-                       idx++;
-               }
-       }
-out:
-       rcu_read_unlock();
-       cb->args[1] = idx;
-       cb->args[0] = h;
-
-       return skb->len;
-}
-
-const struct nla_policy ifla_policy[IFLA_MAX+1] = {
+static const struct nla_policy ifla_policy[IFLA_MAX+1] = {
        [IFLA_IFNAME]           = { .type = NLA_STRING, .len = IFNAMSIZ-1 },
        [IFLA_ADDRESS]          = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
        [IFLA_BROADCAST]        = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
@@ -1196,8 +1150,8 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = {
        [IFLA_NUM_TX_QUEUES]    = { .type = NLA_U32 },
        [IFLA_NUM_RX_QUEUES]    = { .type = NLA_U32 },
        [IFLA_PHYS_PORT_ID]     = { .type = NLA_BINARY, .len = MAX_PHYS_PORT_ID_LEN },
+       [IFLA_CARRIER_CHANGES]  = { .type = NLA_U32 },  /* ignored */
 };
-EXPORT_SYMBOL(ifla_policy);
 
 static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = {
        [IFLA_INFO_KIND]        = { .type = NLA_STRING },
@@ -1235,6 +1189,61 @@ static const struct nla_policy ifla_port_policy[IFLA_PORT_MAX+1] = {
        [IFLA_PORT_RESPONSE]    = { .type = NLA_U16, },
 };
 
+static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
+{
+       struct net *net = sock_net(skb->sk);
+       int h, s_h;
+       int idx = 0, s_idx;
+       struct net_device *dev;
+       struct hlist_head *head;
+       struct nlattr *tb[IFLA_MAX+1];
+       u32 ext_filter_mask = 0;
+
+       s_h = cb->args[0];
+       s_idx = cb->args[1];
+
+       rcu_read_lock();
+       cb->seq = net->dev_base_seq;
+
+       if (nlmsg_parse(cb->nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX,
+                       ifla_policy) >= 0) {
+
+               if (tb[IFLA_EXT_MASK])
+                       ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);
+       }
+
+       for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
+               idx = 0;
+               head = &net->dev_index_head[h];
+               hlist_for_each_entry_rcu(dev, head, index_hlist) {
+                       if (idx < s_idx)
+                               goto cont;
+                       if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK,
+                                            NETLINK_CB(cb->skb).portid,
+                                            cb->nlh->nlmsg_seq, 0,
+                                            NLM_F_MULTI,
+                                            ext_filter_mask) <= 0)
+                               goto out;
+
+                       nl_dump_check_consistent(cb, nlmsg_hdr(skb));
+cont:
+                       idx++;
+               }
+       }
+out:
+       rcu_read_unlock();
+       cb->args[1] = idx;
+       cb->args[0] = h;
+
+       return skb->len;
+}
+
+int rtnl_nla_parse_ifla(struct nlattr **tb, const struct nlattr *head, int len)
+{
+       return nla_parse(tb, IFLA_MAX, head, len, ifla_policy);
+}
+EXPORT_SYMBOL(rtnl_nla_parse_ifla);
+
 struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[])
 {
        struct net *net;
This page took 0.030323 seconds and 5 git commands to generate.