[Devel,rh7,1/3] net: Add ipv6 statistics cpu notifier

Submitted by Kirill Tkhai on Aug. 25, 2016, 1:37 p.m.

Details

Message ID 147213222979.11396.6836379323107175662.stgit@pro
State New
Series "Series without cover letter"
Headers show

Commit Message

Kirill Tkhai Aug. 25, 2016, 1:37 p.m.
Patch adds a notifier, which moves some ipv6 percpu statistics
from died cpu to online cpu.

This allows to do not iterate over all possible cpus during
calculation statistics for a user.

This will be used in next patch.

Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
---
 net/ipv6/af_inet6.c |   52 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

Patch hide | download patch | download mbox

diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 082fdaf..6f4c929 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -44,6 +44,7 @@ 
 #include <linux/netdevice.h>
 #include <linux/icmpv6.h>
 #include <linux/netfilter_ipv6.h>
+#include <linux/cpu.h>
 
 #include <net/ip.h>
 #include <net/ipv6.h>
@@ -700,6 +701,54 @@  bool ipv6_opt_accepted(const struct sock *sk, const struct sk_buff *skb)
 }
 EXPORT_SYMBOL_GPL(ipv6_opt_accepted);
 
+static void move_ipv6_percpu_stats(int cpu, void **mib, int items)
+{
+	int this_cpu, i;
+
+	local_irq_disable();
+	this_cpu = smp_processor_id();
+
+	for (i = 1; i < items; i++) {
+		*(((u64 *) per_cpu_ptr(mib[0], this_cpu)) + i) +=
+		*(((u64 *) per_cpu_ptr(mib[0], cpu)) + i);
+
+		*(((u64 *) per_cpu_ptr(mib[0], cpu)) + i) = 0;
+	}
+	local_irq_enable();
+}
+
+
+static int ipv6_cpu_notify(struct notifier_block *self,
+			   unsigned long action, void *hcpu)
+{
+	int cpu = (unsigned long)hcpu;
+	struct net_device *dev;
+	struct inet6_dev *idev;
+	struct net *net;
+
+	switch (action) {
+		case CPU_DEAD:
+		case CPU_DEAD_FROZEN:
+		rtnl_lock();
+		for_each_net(net) {
+			for_each_netdev(net, dev) {
+				idev = __in6_dev_get(dev);
+				if (!idev)
+					continue;
+				move_ipv6_percpu_stats(cpu,
+						(void **)idev->stats.ipv6,
+						IPSTATS_MIB_MAX);
+			}
+		}
+		rtnl_unlock();
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block ipv6_cpu_notifier = {
+	.notifier_call  = ipv6_cpu_notify,
+};
+
 static struct packet_type ipv6_packet_type __read_mostly = {
 	.type = cpu_to_be16(ETH_P_IPV6),
 	.func = ipv6_rcv,
@@ -951,6 +1000,7 @@  static int __init inet6_init(void)
 	if (err)
 		goto sysctl_fail;
 #endif
+	register_cpu_notifier(&ipv6_cpu_notifier);
 out:
 	return err;
 
@@ -1020,6 +1070,8 @@  static void __exit inet6_exit(void)
 	if (disable_ipv6_mod)
 		return;
 
+	unregister_cpu_notifier(&ipv6_cpu_notifier);
+
 	/* First of all disallow new sockets creation. */
 	sock_unregister(PF_INET6);
 	/* Disallow any further netlink messages */

Comments

Konstantin Khorenko Sept. 8, 2016, 12:06 p.m.
Andrey, please review the patchset.

--
Best regards,

Konstantin Khorenko,
Virtuozzo Linux Kernel Team

On 08/25/2016 04:37 PM, Kirill Tkhai wrote:
> Patch adds a notifier, which moves some ipv6 percpu statistics
> from died cpu to online cpu.
>
> This allows to do not iterate over all possible cpus during
> calculation statistics for a user.
>
> This will be used in next patch.
>
> Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
> ---
>  net/ipv6/af_inet6.c |   52 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 52 insertions(+)
>
> diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
> index 082fdaf..6f4c929 100644
> --- a/net/ipv6/af_inet6.c
> +++ b/net/ipv6/af_inet6.c
> @@ -44,6 +44,7 @@
>  #include <linux/netdevice.h>
>  #include <linux/icmpv6.h>
>  #include <linux/netfilter_ipv6.h>
> +#include <linux/cpu.h>
>
>  #include <net/ip.h>
>  #include <net/ipv6.h>
> @@ -700,6 +701,54 @@ bool ipv6_opt_accepted(const struct sock *sk, const struct sk_buff *skb)
>  }
>  EXPORT_SYMBOL_GPL(ipv6_opt_accepted);
>
> +static void move_ipv6_percpu_stats(int cpu, void **mib, int items)
> +{
> +	int this_cpu, i;
> +
> +	local_irq_disable();
> +	this_cpu = smp_processor_id();
> +
> +	for (i = 1; i < items; i++) {
> +		*(((u64 *) per_cpu_ptr(mib[0], this_cpu)) + i) +=
> +		*(((u64 *) per_cpu_ptr(mib[0], cpu)) + i);
> +
> +		*(((u64 *) per_cpu_ptr(mib[0], cpu)) + i) = 0;
> +	}
> +	local_irq_enable();
> +}
> +
> +
> +static int ipv6_cpu_notify(struct notifier_block *self,
> +			   unsigned long action, void *hcpu)
> +{
> +	int cpu = (unsigned long)hcpu;
> +	struct net_device *dev;
> +	struct inet6_dev *idev;
> +	struct net *net;
> +
> +	switch (action) {
> +		case CPU_DEAD:
> +		case CPU_DEAD_FROZEN:
> +		rtnl_lock();
> +		for_each_net(net) {
> +			for_each_netdev(net, dev) {
> +				idev = __in6_dev_get(dev);
> +				if (!idev)
> +					continue;
> +				move_ipv6_percpu_stats(cpu,
> +						(void **)idev->stats.ipv6,
> +						IPSTATS_MIB_MAX);
> +			}
> +		}
> +		rtnl_unlock();
> +	}
> +	return NOTIFY_OK;
> +}
> +
> +static struct notifier_block ipv6_cpu_notifier = {
> +	.notifier_call  = ipv6_cpu_notify,
> +};
> +
>  static struct packet_type ipv6_packet_type __read_mostly = {
>  	.type = cpu_to_be16(ETH_P_IPV6),
>  	.func = ipv6_rcv,
> @@ -951,6 +1000,7 @@ static int __init inet6_init(void)
>  	if (err)
>  		goto sysctl_fail;
>  #endif
> +	register_cpu_notifier(&ipv6_cpu_notifier);
>  out:
>  	return err;
>
> @@ -1020,6 +1070,8 @@ static void __exit inet6_exit(void)
>  	if (disable_ipv6_mod)
>  		return;
>
> +	unregister_cpu_notifier(&ipv6_cpu_notifier);
> +
>  	/* First of all disallow new sockets creation. */
>  	sock_unregister(PF_INET6);
>  	/* Disallow any further netlink messages */
>
> _______________________________________________
> Devel mailing list
> Devel@openvz.org
> https://lists.openvz.org/mailman/listinfo/devel
> .
>
Andrey Vagin Sept. 13, 2016, 8:26 a.m.
Reviewed-by: Andrei Vagin <avagin@virtuozzo.com>

On Thu, Sep 08, 2016 at 03:06:40PM +0300, Konstantin Khorenko wrote:
> Andrey, please review the patchset.
> 
> --
> Best regards,
> 
> Konstantin Khorenko,
> Virtuozzo Linux Kernel Team
> 
> On 08/25/2016 04:37 PM, Kirill Tkhai wrote:
> > Patch adds a notifier, which moves some ipv6 percpu statistics
> > from died cpu to online cpu.
> > 
> > This allows to do not iterate over all possible cpus during
> > calculation statistics for a user.
> > 
> > This will be used in next patch.
> > 
> > Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
> > ---
> >  net/ipv6/af_inet6.c |   52 +++++++++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 52 insertions(+)
> > 
> > diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
> > index 082fdaf..6f4c929 100644
> > --- a/net/ipv6/af_inet6.c
> > +++ b/net/ipv6/af_inet6.c
> > @@ -44,6 +44,7 @@
> >  #include <linux/netdevice.h>
> >  #include <linux/icmpv6.h>
> >  #include <linux/netfilter_ipv6.h>
> > +#include <linux/cpu.h>
> > 
> >  #include <net/ip.h>
> >  #include <net/ipv6.h>
> > @@ -700,6 +701,54 @@ bool ipv6_opt_accepted(const struct sock *sk, const struct sk_buff *skb)
> >  }
> >  EXPORT_SYMBOL_GPL(ipv6_opt_accepted);
> > 
> > +static void move_ipv6_percpu_stats(int cpu, void **mib, int items)
> > +{
> > +	int this_cpu, i;
> > +
> > +	local_irq_disable();
> > +	this_cpu = smp_processor_id();
> > +
> > +	for (i = 1; i < items; i++) {
> > +		*(((u64 *) per_cpu_ptr(mib[0], this_cpu)) + i) +=
> > +		*(((u64 *) per_cpu_ptr(mib[0], cpu)) + i);
> > +
> > +		*(((u64 *) per_cpu_ptr(mib[0], cpu)) + i) = 0;
> > +	}
> > +	local_irq_enable();
> > +}
> > +
> > +
> > +static int ipv6_cpu_notify(struct notifier_block *self,
> > +			   unsigned long action, void *hcpu)
> > +{
> > +	int cpu = (unsigned long)hcpu;
> > +	struct net_device *dev;
> > +	struct inet6_dev *idev;
> > +	struct net *net;
> > +
> > +	switch (action) {
> > +		case CPU_DEAD:
> > +		case CPU_DEAD_FROZEN:
> > +		rtnl_lock();
> > +		for_each_net(net) {
> > +			for_each_netdev(net, dev) {
> > +				idev = __in6_dev_get(dev);
> > +				if (!idev)
> > +					continue;
> > +				move_ipv6_percpu_stats(cpu,
> > +						(void **)idev->stats.ipv6,
> > +						IPSTATS_MIB_MAX);
> > +			}
> > +		}
> > +		rtnl_unlock();
> > +	}
> > +	return NOTIFY_OK;
> > +}
> > +
> > +static struct notifier_block ipv6_cpu_notifier = {
> > +	.notifier_call  = ipv6_cpu_notify,
> > +};
> > +
> >  static struct packet_type ipv6_packet_type __read_mostly = {
> >  	.type = cpu_to_be16(ETH_P_IPV6),
> >  	.func = ipv6_rcv,
> > @@ -951,6 +1000,7 @@ static int __init inet6_init(void)
> >  	if (err)
> >  		goto sysctl_fail;
> >  #endif
> > +	register_cpu_notifier(&ipv6_cpu_notifier);
> >  out:
> >  	return err;
> > 
> > @@ -1020,6 +1070,8 @@ static void __exit inet6_exit(void)
> >  	if (disable_ipv6_mod)
> >  		return;
> > 
> > +	unregister_cpu_notifier(&ipv6_cpu_notifier);
> > +
> >  	/* First of all disallow new sockets creation. */
> >  	sock_unregister(PF_INET6);
> >  	/* Disallow any further netlink messages */
> > 
> > _______________________________________________
> > Devel mailing list
> > Devel@openvz.org
> > https://lists.openvz.org/mailman/listinfo/devel
> > .
> >