[PATCH RFC 2/3] Add qdisc_stats_broadcast_interval sysctl parameter, and use it to limit stats broadcast interval.

Toke Høiland-Jørgensen toke at toke.dk
Mon Jun 10 05:39:48 PDT 2013


---
 include/net/netns/ipv4.h   |  4 ++++
 include/net/sch_generic.h  |  4 ++++
 net/ipv4/sysctl_net_ipv4.c | 13 +++++++++++++
 net/sched/sch_api.c        |  7 +++++++
 net/sched/sch_generic.c    | 18 ++++++++++++++++++
 5 files changed, 46 insertions(+)

diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h
index 2ba9de8..ff69564 100644
--- a/include/net/netns/ipv4.h
+++ b/include/net/netns/ipv4.h
@@ -64,6 +64,10 @@ struct netns_ipv4 {
 
 	int sysctl_tcp_ecn;
 
+#ifdef CONFIG_NET_SCH_BROADCAST_STATS
+	int sysctl_qdisc_stats_broadcast_interval;
+#endif
+
 	kgid_t sysctl_ping_group_range[2];
 	long sysctl_tcp_mem[3];
 
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index f10818f..92f26cf 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -78,6 +78,10 @@ struct Qdisc {
 	struct netdev_queue	*dev_queue;
 	struct Qdisc		*next_sched;
 
+#ifdef CONFIG_NET_SCH_BROADCAST_STATS
+	u64 			last_stats_broadcast;
+#endif
+
 	struct sk_buff		*gso_skb;
 	/*
 	 * For performance sake on SMP, we put highly modified fields at the end
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 960fd29..896429c 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -851,6 +851,15 @@ static struct ctl_table ipv4_net_table[] = {
 		.mode		= 0644,
 		.proc_handler	= ipv4_tcp_mem,
 	},
+#ifdef CONFIG_NET_SCH_BROADCAST_STATS
+	{
+		.procname	= "qdisc_stats_broadcast_interval",
+		.data		= &init_net.ipv4.sysctl_qdisc_stats_broadcast_interval,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec
+	},
+#endif
 	{ }
 };
 
@@ -880,6 +889,10 @@ static __net_init int ipv4_sysctl_init_net(struct net *net)
 			&net->ipv4.sysctl_ping_group_range;
 		table[7].data =
 			&net->ipv4.sysctl_tcp_ecn;
+#ifdef CONFIG_NET_SCH_BROADCAST_STATS
+		table[9].data =
+			&net->ipv4.sysctl_qdisc_stats_broadcast_interval;
+#endif
 
 		/* Don't export sysctls to unprivileged users */
 		if (net->user_ns != &init_user_ns)
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index c297e2a..154b316 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -1772,6 +1772,10 @@ static int __net_init psched_net_init(struct net *net)
 	if (e == NULL)
 		return -ENOMEM;
 
+#ifdef CONFIG_NET_SCH_BROADCAST_STATS
+	net->ipv4.sysctl_qdisc_stats_broadcast_interval = 200000;
+#endif
+
 	return 0;
 }
 
@@ -1782,6 +1786,9 @@ static void __net_exit psched_net_exit(struct net *net)
 #else
 static int __net_init psched_net_init(struct net *net)
 {
+#ifdef CONFIG_NET_SCH_BROADCAST_STATS
+	net->ipv4.sysctl_qdisc_stats_broadcast_interval = 200000;
+#endif
 	return 0;
 }
 
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 56490a1..1b4e16d 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -150,6 +150,13 @@ int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q,
 }
 
 #ifdef CONFIG_NET_SCH_BROADCAST_STATS
+static inline u64 qdisc_stats_time(void)
+{
+	u64 ns = ktime_to_ns(ktime_get());
+	do_div(ns, NSEC_PER_USEC);
+	return ns;
+}
+
 int qdisc_broadcast_stats(struct Qdisc *q)
 {
 	struct tcmsg *tcm;
@@ -157,10 +164,16 @@ int qdisc_broadcast_stats(struct Qdisc *q)
 	struct gnet_dump d;
 	struct sk_buff *skb;
 	unsigned char *b;
+	u64 time;
 
 	if(!q->dev_queue || !q->dev_queue->dev)
 		return 0;
 
+	time = qdisc_stats_time();
+	if(time < q->last_stats_broadcast +
+		dev_net(qdisc_dev(q))->ipv4.sysctl_qdisc_stats_broadcast_interval)
+		return 0;
+
 	printk(KERN_DEBUG "Packet dequeue, ifname %s(%d), qdisc %s, qlen %d\n",
 		qdisc_dev(q)->name,
 		qdisc_dev(q)->ifindex,
@@ -205,6 +218,8 @@ int qdisc_broadcast_stats(struct Qdisc *q)
 
 	rtnetlink_send(skb, qdisc_dev(q)->nd_net, 0, RTNLGRP_TC_STATS, 0);
 
+	q->last_stats_broadcast = time;
+
 	return 0;
 
 nla_put_failure:
@@ -636,6 +651,9 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
 	sch->enqueue = ops->enqueue;
 	sch->dequeue = ops->dequeue;
 	sch->dev_queue = dev_queue;
+#ifdef CONFIG_NET_SCH_BROADCAST_STATS
+	sch->last_stats_broadcast = qdisc_stats_time();
+#endif
 	dev_hold(dev);
 	atomic_set(&sch->refcnt, 1);
 
-- 
1.8.3



More information about the Bloat-devel mailing list