[Devel,RHEL7,COMMIT] net: Add ipv6 statistics cpu notifier

Submitted by Konstantin Khorenko on Sept. 13, 2016, 11:39 a.m.

Details

Message ID 201609131139.u8DBdY7O024179@finist_cl7.x64_64.work.ct
State New
Series "Series without cover letter"
Headers show

Commit Message

Konstantin Khorenko Sept. 13, 2016, 11:39 a.m.
The commit is pushed to "branch-rh7-3.10.0-327.28.2.vz7.17.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-327.28.2.vz7.17.6
------>
commit cdab282870d72217a03760174fbe96429211b62f
Author: Kirill Tkhai <ktkhai@virtuozzo.com>
Date:   Tue Sep 13 15:39:34 2016 +0400

    net: Add ipv6 statistics cpu notifier
    
    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>
    Reviewed-by: Andrei Vagin <avagin@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 9527549..32c38f8 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>
@@ -701,6 +702,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,
@@ -952,6 +1001,7 @@  static int __init inet6_init(void)
 	if (err)
 		goto sysctl_fail;
 #endif
+	register_cpu_notifier(&ipv6_cpu_notifier);
 out:
 	return err;
 
@@ -1021,6 +1071,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 */