summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2007-04-20 15:56:20 -0700
committerDavid S. Miller <davem@sunset.davemloft.net>2007-04-25 22:29:10 -0700
commitbf99f1bde3b3009af74874f3465f6861431fbb66 (patch)
treeec3ee5ca8e95e090d65671d74994b7729058c845
parent628a5c561890a9a9a74dea017873530584aab06e (diff)
downloadlinux-bf99f1bde3b3009af74874f3465f6861431fbb66.tar.gz
linux-bf99f1bde3b3009af74874f3465f6861431fbb66.tar.xz
[IPV6] SNMP: Netlink interface.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/if_link.h1
-rw-r--r--include/net/ipv6.h1
-rw-r--r--net/ipv6/addrconf.c22
-rw-r--r--net/ipv6/proc.c32
4 files changed, 51 insertions, 5 deletions
diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index 35ed3b5467f3..604c2434f71c 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -126,6 +126,7 @@ enum
IFLA_INET6_STATS, /* statistics */
IFLA_INET6_MCAST, /* MC things. What of them? */
IFLA_INET6_CACHEINFO, /* time values and max reasm size */
+ IFLA_INET6_ICMP6STATS, /* statistics (icmpv6) */
__IFLA_INET6_MAX
};
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 00328b71a08c..4408def379bf 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -172,6 +172,7 @@ int snmp6_alloc_dev(struct inet6_dev *idev);
int snmp6_free_dev(struct inet6_dev *idev);
int snmp6_mib_init(void *ptr[2], size_t mibsize, size_t mibalign);
void snmp6_mib_free(void *ptr[2]);
+void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype, int bytes);
struct ip6_ra_chain
{
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 1486f76f7878..9ba9e92d1934 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -3433,6 +3433,8 @@ static inline size_t inet6_if_nlmsg_size(void)
nla_total_size(4) /* IFLA_INET6_FLAGS */
+ nla_total_size(sizeof(struct ifla_cacheinfo))
+ nla_total_size(DEVCONF_MAX * 4) /* IFLA_INET6_CONF */
+ + nla_total_size(IPSTATS_MIB_MAX * 8) /* IFLA_INET6_STATS */
+ + nla_total_size(ICMP6_MIB_MAX * 8) /* IFLA_INET6_ICMP6STATS */
);
}
@@ -3440,7 +3442,7 @@ static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev,
u32 pid, u32 seq, int event, unsigned int flags)
{
struct net_device *dev = idev->dev;
- struct nlattr *conf;
+ struct nlattr *nla;
struct ifinfomsg *hdr;
struct nlmsghdr *nlh;
void *protoinfo;
@@ -3480,12 +3482,22 @@ static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev,
ci.retrans_time = idev->nd_parms->retrans_time;
NLA_PUT(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci);
- conf = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32));
- if (conf == NULL)
+ nla = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32));
+ if (nla == NULL)
goto nla_put_failure;
- ipv6_store_devconf(&idev->cnf, nla_data(conf), nla_len(conf));
+ ipv6_store_devconf(&idev->cnf, nla_data(nla), nla_len(nla));
- /* XXX - Statistics/MC not implemented */
+ /* XXX - MC not implemented */
+
+ nla = nla_reserve(skb, IFLA_INET6_STATS, IPSTATS_MIB_MAX * sizeof(u64));
+ if (nla == NULL)
+ goto nla_put_failure;
+ snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_STATS, nla_len(nla));
+
+ nla = nla_reserve(skb, IFLA_INET6_ICMP6STATS, ICMP6_MIB_MAX * sizeof(u64));
+ if (nla == NULL)
+ goto nla_put_failure;
+ snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_ICMP6STATS, nla_len(nla));
nla_nest_end(skb, protoinfo);
return nlmsg_end(skb, nlh);
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c
index fa3fb509f187..0dc551501519 100644
--- a/net/ipv6/proc.c
+++ b/net/ipv6/proc.c
@@ -207,6 +207,31 @@ static const struct file_operations snmp6_seq_fops = {
.release = single_release,
};
+static inline void
+__snmp6_fill_stats(u64 *stats, void **mib, int items, int bytes)
+{
+ int i;
+ int pad = bytes - sizeof(u64) * items;
+ BUG_ON(pad < 0);
+ stats[0] = items;
+ for (i = 1; i < items; i++)
+ stats[i] = (u64)fold_field(mib, i);
+ memset(&stats[items], 0, pad);
+}
+
+void
+snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype, int bytes)
+{
+ switch(attrtype) {
+ case IFLA_INET6_STATS:
+ __snmp6_fill_stats(stats, (void **)idev->stats.ipv6, IPSTATS_MIB_MAX, bytes);
+ break;
+ case IFLA_INET6_ICMP6STATS:
+ __snmp6_fill_stats(stats, (void **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes);
+ break;
+ }
+}
+
int snmp6_register_dev(struct inet6_dev *idev)
{
struct proc_dir_entry *p;
@@ -283,6 +308,13 @@ int snmp6_unregister_dev(struct inet6_dev *idev)
{
return 0;
}
+
+void
+snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype, int bytes)
+{
+ memset(stats, 0, sizeof(bytes));
+}
+
#endif /* CONFIG_PROC_FS */
int snmp6_alloc_dev(struct inet6_dev *idev)