From bf99f1bde3b3009af74874f3465f6861431fbb66 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Fri, 20 Apr 2007 15:56:20 -0700 Subject: [IPV6] SNMP: Netlink interface. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/proc.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'net/ipv6/proc.c') 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) -- cgit From 49ed67a9eee3c756263feed4474e4fcf5c8eaed2 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Fri, 20 Apr 2007 15:56:48 -0700 Subject: [IPV6] SNMP: Move some statistic bits to net/ipv6/proc.c. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/af_inet6.c | 33 --------------------------------- net/ipv6/proc.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 33 deletions(-) (limited to 'net/ipv6/proc.c') diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index df31cdd33cda..825d03e87ae0 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -712,39 +712,6 @@ int ipv6_opt_accepted(struct sock *sk, struct sk_buff *skb) EXPORT_SYMBOL_GPL(ipv6_opt_accepted); -int -snmp6_mib_init(void *ptr[2], size_t mibsize, size_t mibalign) -{ - if (ptr == NULL) - return -EINVAL; - - ptr[0] = __alloc_percpu(mibsize); - if (!ptr[0]) - goto err0; - - ptr[1] = __alloc_percpu(mibsize); - if (!ptr[1]) - goto err1; - - return 0; - -err1: - free_percpu(ptr[0]); - ptr[0] = NULL; -err0: - return -ENOMEM; -} - -void -snmp6_mib_free(void *ptr[2]) -{ - if (ptr == NULL) - return; - free_percpu(ptr[0]); - free_percpu(ptr[1]); - ptr[0] = ptr[1] = NULL; -} - static int __init init_ipv6_mibs(void) { if (snmp6_mib_init((void **)ipv6_statistics, sizeof (struct ipstats_mib), diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 0dc551501519..5c3ce1c687c9 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -346,4 +346,34 @@ int snmp6_free_dev(struct inet6_dev *idev) return 0; } +int snmp6_mib_init(void *ptr[2], size_t mibsize, size_t mibalign) +{ + if (ptr == NULL) + return -EINVAL; + + ptr[0] = __alloc_percpu(mibsize); + if (!ptr[0]) + goto err0; + + ptr[1] = __alloc_percpu(mibsize); + if (!ptr[1]) + goto err1; + + return 0; + +err1: + free_percpu(ptr[0]); + ptr[0] = NULL; +err0: + return -ENOMEM; +} + +void snmp6_mib_free(void *ptr[2]) +{ + if (ptr == NULL) + return; + free_percpu(ptr[0]); + free_percpu(ptr[1]); + ptr[0] = ptr[1] = NULL; +} -- cgit From 1370b5a59b941ac3873b5e8614d496e9f481d670 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Fri, 20 Apr 2007 15:57:45 -0700 Subject: [IPV6] SNMP: Export statistics via netlink without CONFIG_PROC_FS. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/proc.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'net/ipv6/proc.c') diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 5c3ce1c687c9..c847cef626a8 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -141,6 +141,7 @@ static struct snmp_mib snmp6_udplite6_list[] = { SNMP_MIB_ITEM("UdpLite6OutDatagrams", UDP_MIB_OUTDATAGRAMS), SNMP_MIB_SENTINEL }; +#endif /* CONFIG_PROC_FS */ static unsigned long fold_field(void *mib[], int offt) @@ -155,6 +156,7 @@ fold_field(void *mib[], int offt) return res; } +#ifdef CONFIG_PROC_FS static inline void snmp6_seq_show_item(struct seq_file *seq, void **mib, struct snmp_mib *itemlist) { @@ -206,6 +208,7 @@ static const struct file_operations snmp6_seq_fops = { .llseek = seq_lseek, .release = single_release, }; +#endif /* CONFIG_PROC_FS */ static inline void __snmp6_fill_stats(u64 *stats, void **mib, int items, int bytes) @@ -232,6 +235,7 @@ snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype, int bytes) } } +#ifdef CONFIG_PROC_FS int snmp6_register_dev(struct inet6_dev *idev) { struct proc_dir_entry *p; @@ -309,12 +313,6 @@ 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) -- cgit From 2334e973559e119fa4161047035f03ad97a8676a Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Sat, 21 Apr 2007 20:12:43 +0900 Subject: [IPV6] SNMP: Avoid unaligned accesses. Because stats pointer may not be aligned for u64, use memcpy to fill u64 values. Issue reported by David Miller . Signed-off-by: YOSHIFUJI Hideaki --- include/net/ipv6.h | 2 +- net/ipv6/proc.c | 22 ++++++++++++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) (limited to 'net/ipv6/proc.c') diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 4408def379bf..1df360eb0791 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -172,7 +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); +void snmp6_fill_stats(void *stats, struct inet6_dev *idev, int attrtype, int bytes); struct ip6_ra_chain { diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index c847cef626a8..aba94316b773 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -210,20 +210,30 @@ static const struct file_operations snmp6_seq_fops = { }; #endif /* CONFIG_PROC_FS */ +/* + * Stats may not be aligned for u64, so use memcpy to avoid + * unaligned accesses. + */ +static inline void __set_u64(void *p, u64 v) +{ + memcpy(p, &v, sizeof(u64)); +} + static inline void -__snmp6_fill_stats(u64 *stats, void **mib, int items, int bytes) +__snmp6_fill_stats(void *stats, void **mib, int items, int bytes) { int i; + u8 *p = stats; 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); + __set_u64(p, items); + for (i = 1, p += sizeof(u64); i < items; i++, p += sizeof(u64)) + __set_u64(p, fold_field(mib, i)); + memset(p, 0, pad); } void -snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype, int bytes) +snmp6_fill_stats(void *stats, struct inet6_dev *idev, int attrtype, int bytes) { switch(attrtype) { case IFLA_INET6_STATS: -- cgit From 97fc8d0bc58cd09e62dc06ea5a64b58841738934 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Sat, 21 Apr 2007 19:52:04 -0700 Subject: [IPV6] SNMP: Use put_unaligned() instead of memcpy(). Hint from David Miller . Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- include/net/ipv6.h | 2 +- net/ipv6/proc.c | 26 ++++++++++---------------- 2 files changed, 11 insertions(+), 17 deletions(-) (limited to 'net/ipv6/proc.c') diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 1df360eb0791..4408def379bf 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -172,7 +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(void *stats, struct inet6_dev *idev, int attrtype, int bytes); +void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype, int bytes); struct ip6_ra_chain { diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index aba94316b773..7a00bedb6b93 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -210,30 +211,23 @@ static const struct file_operations snmp6_seq_fops = { }; #endif /* CONFIG_PROC_FS */ -/* - * Stats may not be aligned for u64, so use memcpy to avoid - * unaligned accesses. - */ -static inline void __set_u64(void *p, u64 v) -{ - memcpy(p, &v, sizeof(u64)); -} - static inline void -__snmp6_fill_stats(void *stats, void **mib, int items, int bytes) +__snmp6_fill_stats(u64 *stats, void **mib, int items, int bytes) { int i; - u8 *p = stats; int pad = bytes - sizeof(u64) * items; BUG_ON(pad < 0); - __set_u64(p, items); - for (i = 1, p += sizeof(u64); i < items; i++, p += sizeof(u64)) - __set_u64(p, fold_field(mib, i)); - memset(p, 0, pad); + + /* Use put_unaligned() because stats may not be aligned for u64. */ + put_unaligned(items, &stats[0]); + for (i = 1; i < items; i++) + put_unaligned(fold_field(mib, i), &stats[i]); + + memset(&stats[items], 0, pad); } void -snmp6_fill_stats(void *stats, struct inet6_dev *idev, int attrtype, int bytes) +snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype, int bytes) { switch(attrtype) { case IFLA_INET6_STATS: -- cgit From 7f7d9a6b96c5708c5184cbed61bbc15b163a0f08 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 24 Apr 2007 21:54:09 -0700 Subject: [IPV6]: Consolidate common SNMP code This patch moves the non-proc SNMP code into addrconf.c and reuses IPv4 SNMP code where applicable. As a result we can skip proc.o if /proc is disabled. Note that I've made a number of functions static since they're only used by addrconf.c for now. If they ever get used elsewhere we can always remove the static. Signed-off-by: Herbert Xu Acked-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- include/net/ipv6.h | 20 +++++---- net/ipv6/Makefile | 3 +- net/ipv6/addrconf.c | 60 +++++++++++++++++++++++++ net/ipv6/af_inet6.c | 30 ++++++------- net/ipv6/proc.c | 125 +--------------------------------------------------- 5 files changed, 91 insertions(+), 147 deletions(-) (limited to 'net/ipv6/proc.c') diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 4408def379bf..f70afef9c3cc 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -166,14 +166,6 @@ DECLARE_SNMP_STAT(struct udp_mib, udplite_stats_in6); if (is_udplite) SNMP_INC_STATS_USER(udplite_stats_in6, field); \ else SNMP_INC_STATS_USER(udp_stats_in6, field); } while(0) -int snmp6_register_dev(struct inet6_dev *idev); -int snmp6_unregister_dev(struct inet6_dev *idev); -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 { struct ip6_ra_chain *next; @@ -606,8 +598,20 @@ extern int udplite6_proc_init(void); extern void udplite6_proc_exit(void); extern int ipv6_misc_proc_init(void); extern void ipv6_misc_proc_exit(void); +extern int snmp6_register_dev(struct inet6_dev *idev); +extern int snmp6_unregister_dev(struct inet6_dev *idev); extern struct rt6_statistics rt6_stats; +#else +static inline int snmp6_register_dev(struct inet6_dev *idev) +{ + return 0; +} + +static inline int snmp6_unregister_dev(struct inet6_dev *idev) +{ + return 0; +} #endif #ifdef CONFIG_SYSCTL diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index e9478688c3d3..0acf64dc5775 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile @@ -7,7 +7,7 @@ obj-$(CONFIG_IPV6) += ipv6.o ipv6-objs := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \ route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o udplite.o \ raw.o protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \ - exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \ + exthdrs.o sysctl_net_ipv6.o datagram.o \ ip6_flowlabel.o inet6_connection_sock.o ipv6-$(CONFIG_XFRM) += xfrm6_policy.o xfrm6_state.o xfrm6_input.o \ @@ -28,6 +28,7 @@ obj-$(CONFIG_INET6_XFRM_MODE_TUNNEL) += xfrm6_mode_tunnel.o obj-$(CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION) += xfrm6_mode_ro.o obj-$(CONFIG_INET6_XFRM_MODE_BEET) += xfrm6_mode_beet.o obj-$(CONFIG_NETFILTER) += netfilter/ +obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_IPV6_SIT) += sit.o obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 33ccc95c349b..ea86bf4bfe0a 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -81,6 +81,7 @@ #endif #include +#include #include #include @@ -246,6 +247,37 @@ static void addrconf_mod_timer(struct inet6_ifaddr *ifp, add_timer(&ifp->timer); } +static int snmp6_alloc_dev(struct inet6_dev *idev) +{ + int err = -ENOMEM; + + if (!idev || !idev->dev) + return -EINVAL; + + if (snmp_mib_init((void **)idev->stats.ipv6, + sizeof(struct ipstats_mib), + __alignof__(struct ipstats_mib)) < 0) + goto err_ip; + if (snmp_mib_init((void **)idev->stats.icmpv6, + sizeof(struct icmpv6_mib), + __alignof__(struct icmpv6_mib)) < 0) + goto err_icmp; + + return 0; + +err_icmp: + snmp_mib_free((void **)idev->stats.ipv6); +err_ip: + return err; +} + +static int snmp6_free_dev(struct inet6_dev *idev) +{ + snmp_mib_free((void **)idev->stats.icmpv6); + snmp_mib_free((void **)idev->stats.ipv6); + return 0; +} + /* Nobody refers to this device, we may destroy it. */ static void in6_dev_finish_destroy_rcu(struct rcu_head *head) @@ -3438,6 +3470,34 @@ static inline size_t inet6_if_nlmsg_size(void) ); } +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); + + /* Use put_unaligned() because stats may not be aligned for u64. */ + put_unaligned(items, &stats[0]); + for (i = 1; i < items; i++) + put_unaligned(snmp_fold_field(mib, i), &stats[i]); + + memset(&stats[items], 0, pad); +} + +static 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; + } +} + static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, u32 pid, u32 seq, int event, unsigned int flags) { diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 825d03e87ae0..18cb928c8d92 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -714,26 +714,26 @@ EXPORT_SYMBOL_GPL(ipv6_opt_accepted); static int __init init_ipv6_mibs(void) { - if (snmp6_mib_init((void **)ipv6_statistics, sizeof (struct ipstats_mib), - __alignof__(struct ipstats_mib)) < 0) + if (snmp_mib_init((void **)ipv6_statistics, sizeof (struct ipstats_mib), + __alignof__(struct ipstats_mib)) < 0) goto err_ip_mib; - if (snmp6_mib_init((void **)icmpv6_statistics, sizeof (struct icmpv6_mib), - __alignof__(struct icmpv6_mib)) < 0) + if (snmp_mib_init((void **)icmpv6_statistics, sizeof (struct icmpv6_mib), + __alignof__(struct icmpv6_mib)) < 0) goto err_icmp_mib; - if (snmp6_mib_init((void **)udp_stats_in6, sizeof (struct udp_mib), - __alignof__(struct udp_mib)) < 0) + if (snmp_mib_init((void **)udp_stats_in6, sizeof (struct udp_mib), + __alignof__(struct udp_mib)) < 0) goto err_udp_mib; - if (snmp6_mib_init((void **)udplite_stats_in6, sizeof (struct udp_mib), - __alignof__(struct udp_mib)) < 0) + if (snmp_mib_init((void **)udplite_stats_in6, sizeof (struct udp_mib), + __alignof__(struct udp_mib)) < 0) goto err_udplite_mib; return 0; err_udplite_mib: - snmp6_mib_free((void **)udp_stats_in6); + snmp_mib_free((void **)udp_stats_in6); err_udp_mib: - snmp6_mib_free((void **)icmpv6_statistics); + snmp_mib_free((void **)icmpv6_statistics); err_icmp_mib: - snmp6_mib_free((void **)ipv6_statistics); + snmp_mib_free((void **)ipv6_statistics); err_ip_mib: return -ENOMEM; @@ -741,10 +741,10 @@ err_ip_mib: static void cleanup_ipv6_mibs(void) { - snmp6_mib_free((void **)ipv6_statistics); - snmp6_mib_free((void **)icmpv6_statistics); - snmp6_mib_free((void **)udp_stats_in6); - snmp6_mib_free((void **)udplite_stats_in6); + snmp_mib_free((void **)ipv6_statistics); + snmp_mib_free((void **)icmpv6_statistics); + snmp_mib_free((void **)udp_stats_in6); + snmp_mib_free((void **)udplite_stats_in6); } static int __init inet6_init(void) diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 7a00bedb6b93..acb306a5dd56 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -23,13 +23,12 @@ #include #include #include -#include +#include #include #include #include #include -#ifdef CONFIG_PROC_FS static struct proc_dir_entry *proc_net_devsnmp6; static int fold_prot_inuse(struct proto *proto) @@ -142,29 +141,14 @@ static struct snmp_mib snmp6_udplite6_list[] = { SNMP_MIB_ITEM("UdpLite6OutDatagrams", UDP_MIB_OUTDATAGRAMS), SNMP_MIB_SENTINEL }; -#endif /* CONFIG_PROC_FS */ -static unsigned long -fold_field(void *mib[], int offt) -{ - unsigned long res = 0; - int i; - - for_each_possible_cpu(i) { - res += *(((unsigned long *)per_cpu_ptr(mib[0], i)) + offt); - res += *(((unsigned long *)per_cpu_ptr(mib[1], i)) + offt); - } - return res; -} - -#ifdef CONFIG_PROC_FS static inline void snmp6_seq_show_item(struct seq_file *seq, void **mib, struct snmp_mib *itemlist) { int i; for (i=0; itemlist[i].name; i++) seq_printf(seq, "%-32s\t%lu\n", itemlist[i].name, - fold_field(mib, itemlist[i].entry)); + snmp_fold_field(mib, itemlist[i].entry)); } static int snmp6_seq_show(struct seq_file *seq, void *v) @@ -209,37 +193,7 @@ static const struct file_operations snmp6_seq_fops = { .llseek = seq_lseek, .release = single_release, }; -#endif /* CONFIG_PROC_FS */ -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); - - /* Use put_unaligned() because stats may not be aligned for u64. */ - put_unaligned(items, &stats[0]); - for (i = 1; i < items; i++) - put_unaligned(fold_field(mib, i), &stats[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; - } -} - -#ifdef CONFIG_PROC_FS int snmp6_register_dev(struct inet6_dev *idev) { struct proc_dir_entry *p; @@ -304,78 +258,3 @@ void ipv6_misc_proc_exit(void) proc_net_remove("snmp6"); } -#else /* CONFIG_PROC_FS */ - - -int snmp6_register_dev(struct inet6_dev *idev) -{ - return 0; -} - -int snmp6_unregister_dev(struct inet6_dev *idev) -{ - return 0; -} - -#endif /* CONFIG_PROC_FS */ - -int snmp6_alloc_dev(struct inet6_dev *idev) -{ - int err = -ENOMEM; - - if (!idev || !idev->dev) - return -EINVAL; - - if (snmp6_mib_init((void **)idev->stats.ipv6, sizeof(struct ipstats_mib), - __alignof__(struct ipstats_mib)) < 0) - goto err_ip; - if (snmp6_mib_init((void **)idev->stats.icmpv6, sizeof(struct icmpv6_mib), - __alignof__(struct icmpv6_mib)) < 0) - goto err_icmp; - - return 0; - -err_icmp: - snmp6_mib_free((void **)idev->stats.ipv6); -err_ip: - return err; -} - -int snmp6_free_dev(struct inet6_dev *idev) -{ - snmp6_mib_free((void **)idev->stats.icmpv6); - snmp6_mib_free((void **)idev->stats.ipv6); - return 0; -} - -int snmp6_mib_init(void *ptr[2], size_t mibsize, size_t mibalign) -{ - if (ptr == NULL) - return -EINVAL; - - ptr[0] = __alloc_percpu(mibsize); - if (!ptr[0]) - goto err0; - - ptr[1] = __alloc_percpu(mibsize); - if (!ptr[1]) - goto err1; - - return 0; - -err1: - free_percpu(ptr[0]); - ptr[0] = NULL; -err0: - return -ENOMEM; -} - -void snmp6_mib_free(void *ptr[2]) -{ - if (ptr == NULL) - return; - free_percpu(ptr[0]); - free_percpu(ptr[1]); - ptr[0] = ptr[1] = NULL; -} - -- cgit From 5632c5152aa621885d87ea0b8fdd5a6bb9f69c6f Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sat, 28 Apr 2007 21:16:39 -0700 Subject: [IPV6]: Track device renames in snmp6. When network device's are renamed, the IPV6 snmp6 code gets confused. It doesn't track name changes so it will OOPS when network device's are removed. The fix is trivial, just unregister/re-register in notify handler. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 6 ++++-- net/ipv6/proc.c | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'net/ipv6/proc.c') diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index e04e49373505..3452433cbc96 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -2359,8 +2359,9 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, break; case NETDEV_CHANGENAME: -#ifdef CONFIG_SYSCTL if (idev) { + snmp6_unregister_dev(idev); +#ifdef CONFIG_SYSCTL addrconf_sysctl_unregister(&idev->cnf); neigh_sysctl_unregister(idev->nd_parms); neigh_sysctl_register(dev, idev->nd_parms, @@ -2368,8 +2369,9 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, &ndisc_ifinfo_sysctl_change, NULL); addrconf_sysctl_register(idev, &idev->cnf); - } #endif + snmp6_register_dev(idev); + } break; } diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index acb306a5dd56..920dc9cf6a84 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -223,6 +223,7 @@ int snmp6_unregister_dev(struct inet6_dev *idev) return -EINVAL; remove_proc_entry(idev->stats.proc_dir_entry->name, proc_net_devsnmp6); + idev->stats.proc_dir_entry = NULL; return 0; } -- cgit