Skip to contentSkip to conversation

cgroup: net_cls: traffic counter based on classification control cgroup

RFC PATCH In review Alexey Perevalov 2 participants 2 messages Jan 18, 2013

Subsystems (7)
lore
Share & tools
lore
#0 lore raw

RFC PATCH v4 1/1 cgroup: net_cls: traffic counter based on classification control cgroup

Traffic counter based on classification control group

The main goal of this patch it's counting traffic for process placed to net_cls cgroup (ingress and egress).
It's based on atomic and holds counter per network interfaces.

It handles packets in net/core/dev.c for egress and in /net/ipv4/tcp.c|udp.c for ingress.

Cgroup fs interface provides following files additional to existing
net_cls files:
net_cls.ifacename.usage_in_bytes Containing rcv/snd lines.

---
 Documentation/cgroups/net_cls.txt |   20 ++++
 include/net/cls_cgroup.h          |  200 +++++++++++++++++++++++++++++++++----
 include/net/cls_counter_holder.h  |   26 +++++
 init/Kconfig                      |   25 +++++
 kernel/cgroup.c                   |    2 +
 kernel/res_counter.c              |    4 +
 net/core/dev.c                    |    6 ++
 net/ipv4/tcp.c                    |   27 ++++-
 net/ipv4/udp.c                    |    6 ++
 net/sched/Kconfig                 |   11 --
 net/sched/Makefile                |    1 +
 net/sched/cls_cgroup.c            |  194 ++++++++++++++++++++++++++++++++++-
 net/sched/cls_counter_holder.c    |  144 ++++++++++++++++++++++++++
 13 files changed, 631 insertions(+), 35 deletions(-)
 create mode 100644 Documentation/cgroups/net_cls.txt
 create mode 100644 include/net/cls_counter_holder.h
 create mode 100644 net/sched/cls_counter_holder.c
Documentation/cgroups/net_cls.txt new file +20 -0
new file mode 100644
index 0000000..131fbf1
@@ -0,0 +1,20 @@
+Network packet classification cgroup
+--------------------------------------
+
+The net_cls cgroup is attended to mark engress network packets with special
+identifier (classid). The main purpose of marking packets with classid is
+using it in linux QoS mechanism. It is needed to tweak TC rules for cgroup
+related processes.
+
+Cgroup net_cls marks engress packets in sk_alloc.
+
+Also this cgroup provides ability to count network traffic per network
+interface and provides it in according files.
+
+File system representation of cgroup consists of the standart for cgroupfs
+files like tasks, cgroup.procs, cgroup.clone_children, cgroup.event_control.
+
+Net_cls cgroup introduces they own net_cls.classid.
+Counting part contains counter file with the following names:
+net_cls.iface_name.usage_in_bytes
+consists of 2 lines with rcv and snd.
include/net/cls_cgroup.h +180 -20

239 lines not on this page · raw message

include/net/cls_counter_holder.h new file +26 -0
new file mode 100644
index 0000000..a129baa
@@ -0,0 +1,26 @@
+/*
+ * cls_counter_holder.c  Interface for holding references of the
+ *                       net cls cgroup instances.
+ *
+ * Authors:	Alexey Perevalov, <[email protected]>
+ *
+ * Changes:
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _NET_CLS_COUNTER_HOLDER_H_
+#define _NET_CLS_COUNTER_HOLDER_H_
+
+#include <net/cls_cgroup.h>
+
+struct cgroup_cls_state;
+
+void insert_cls_cgroup_entry(struct cgroup_cls_state *obj);
+void delete_cls_cgroup_entry(const u32 classid);
+struct cgroup_cls_state *find_cls_cgroup_by_classid(const u32 classid);
+
+
+#endif /* _NET_CLS_COUNTER_HOLDER_H_ */
init/Kconfig +25 -0
index 7d30240..6e01fc2 100644
@@ -906,6 +906,31 @@ config CGROUP_HUGETLB
 	  control group is tracked in the third page lru pointer. This means
 	  that we cannot use the controller with huge page less than 3 pages.
 
+menuconfig NET_CLS_CGROUP
+	tristate "Control Group Classifier"
+	select NET_CLS
+	depends on CGROUPS
+	---help---
+	  Say Y here if you want to classify packets based on the control
+	  cgroup of their process.
+
+	  To compile this code as a module, choose M here: the
+	  module will be called cls_cgroup.
+
+if NET_CLS_CGROUP
+config NET_CLS_COUNTER
+	bool "Network traffic counter for network Control Group Classifier"
+	select NET_CLS
+	default n
+	depends on NET_CLS_CGROUP && RESOURCE_COUNTERS
+	---help---
+	  Say Y here if you want to count traffic associate with the control
+	  cgroup.
+
+	  To add functionality to cls_cgroup select y.
+
+endif #NET_CLS_CGROUP
+
 config CGROUP_PERF
 	bool "Enable perf_event per-cpu per-container group (cgroup) monitoring"
 	depends on PERF_EVENTS && CGROUPS
kernel/cgroup.c +2 -0
index 4855892..cd82a9e 100644
@@ -2897,6 +2897,8 @@ int cgroup_rm_cftypes(struct cgroup_subsys *ss, struct cftype *cfts)
 	cgroup_cfts_commit(ss, NULL, false);
 	return -ENOENT;
 }
+EXPORT_SYMBOL_GPL(cgroup_rm_cftypes);
+
 
 /**
  * cgroup_task_count - count the number of tasks in a cgroup.
kernel/res_counter.c +4 -0
index ff55247..a51b501 100644
@@ -13,6 +13,8 @@
 #include <linux/res_counter.h>
 #include <linux/uaccess.h>
 #include <linux/mm.h>
+#include <linux/export.h>
+
 
 void res_counter_init(struct res_counter *counter, struct res_counter *parent)
 {
@@ -21,6 +23,7 @@ void res_counter_init(struct res_counter *counter, struct res_counter *parent)
 	counter->soft_limit = RESOURCE_MAX;
 	counter->parent = parent;
 }
+EXPORT_SYMBOL(res_counter_init);
 
 int res_counter_charge_locked(struct res_counter *counter, unsigned long val,
 			      bool force)
@@ -176,6 +179,7 @@ u64 res_counter_read_u64(struct res_counter *counter, int member)
 	return *res_counter_member(counter, member);
 }
 #endif
+EXPORT_SYMBOL(res_counter_read_u64);
 
 int res_counter_memparse_write_strategy(const char *buf,
 					unsigned long long *res)
net/core/dev.c +6 -0
index d1e8116..ffc9ec2 100644
@@ -135,6 +135,7 @@
 #include <linux/net_tstamp.h>
 #include <linux/static_key.h>
 #include <net/flow_keys.h>
+#include <net/cls_cgroup.h>
 
 #include "net-sysfs.h"
 
@@ -2922,6 +2923,11 @@ int dev_queue_xmit(struct sk_buff *skb)
 	 */
 	rcu_read_lock_bh();
 
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+	if (dev)
+		count_cls_snd(skb_cls_classid(skb), skb->len, dev->name);
+#endif
+
 	skb_update_prio(skb);
 
 	txq = netdev_pick_tx(dev, skb);
net/ipv4/tcp.c +26 -1
index 1ca2536..dc4dc3a 100644
@@ -276,6 +276,7 @@
 #include <net/ip.h>
 #include <net/netdma.h>
 #include <net/sock.h>
+#include <net/cls_cgroup.h>
 
 #include <asm/uaccess.h>
 #include <asm/ioctls.h>
@@ -1464,6 +1465,9 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
 	u32 seq = tp->copied_seq;
 	u32 offset;
 	int copied = 0;
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+	int ifindex = 0;
+#endif
 
 	if (sk->sk_state == TCP_LISTEN)
 		return -ENOTCONN;
@@ -1510,6 +1514,9 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
 			++seq;
 			break;
 		}
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+		ifindex = get_ifindex_from_skb(skb);
+#endif
 		sk_eat_skb(sk, skb, false);
 		if (!desc->count)
 			break;
@@ -1520,8 +1527,12 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
 	tcp_rcv_space_adjust(sk);
 
 	/* Clean up data we have read: This will do ACK frames. */
-	if (copied > 0)
+	if (copied > 0) {
 		tcp_cleanup_rbuf(sk, copied);
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+		count_cls_rcv(current, copied, ifindex);
+#endif
+	}
 	return copied;
 }
 EXPORT_SYMBOL(tcp_read_sock);
@@ -1549,6 +1560,9 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 	bool copied_early = false;
 	struct sk_buff *skb;
 	u32 urg_hole = 0;
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+	int ifindex = 0;
+#endif
 
 	lock_sock(sk);
 
@@ -1873,6 +1887,9 @@ skip_copy:
 		if (tcp_hdr(skb)->fin)
 			goto found_fin_ok;
 		if (!(flags & MSG_PEEK)) {
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+			ifindex = get_ifindex_from_skb(skb);
+#endif
 			sk_eat_skb(sk, skb, copied_early);
 			copied_early = false;
 		}
@@ -1882,6 +1899,9 @@ skip_copy:
 		/* Process the FIN. */
 		++*seq;
 		if (!(flags & MSG_PEEK)) {
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+			ifindex = get_ifindex_from_skb(skb);
+#endif
 			sk_eat_skb(sk, skb, copied_early);
 			copied_early = false;
 		}
@@ -1924,6 +1944,11 @@ skip_copy:
 	/* Clean up data we have read: This will do ACK frames. */
 	tcp_cleanup_rbuf(sk, copied);
 
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+	if (copied > 0)
+		count_cls_rcv(current, copied, ifindex);
+#endif
+
 	release_sock(sk);
 	return copied;
 
net/ipv4/udp.c +6 -0
index 79c8dbe..a143629 100644
@@ -101,6 +101,7 @@
 #include <linux/skbuff.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#include <net/cls_cgroup.h>
 #include <net/net_namespace.h>
 #include <net/icmp.h>
 #include <net/route.h>
@@ -1254,6 +1255,11 @@ try_again:
 	if (flags & MSG_TRUNC)
 		err = ulen;
 
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+	if (ulen > 0)
+		count_cls_rcv(current, ulen, get_ifindex_from_skb(skb));
+#endif
+
 out_free:
 	skb_free_datagram_locked(sk, skb);
 out:
net/sched/Kconfig +0 -11
index 235e01a..ac7bcdb 100644
@@ -418,17 +418,6 @@ config NET_CLS_FLOW
 	  To compile this code as a module, choose M here: the
 	  module will be called cls_flow.
 
-config NET_CLS_CGROUP
-	tristate "Control Group Classifier"
-	select NET_CLS
-	depends on CGROUPS
-	---help---
-	  Say Y here if you want to classify packets based on the control
-	  cgroup of their process.
-
-	  To compile this code as a module, choose M here: the
-	  module will be called cls_cgroup.
-
 config NET_EMATCH
 	bool "Extended Matches"
 	select NET_CLS
net/sched/Makefile +1 -0
index 978cbf0..95dbb12 100644
@@ -49,6 +49,7 @@ obj-$(CONFIG_NET_CLS_RSVP6)	+= cls_rsvp6.o
 obj-$(CONFIG_NET_CLS_BASIC)	+= cls_basic.o
 obj-$(CONFIG_NET_CLS_FLOW)	+= cls_flow.o
 obj-$(CONFIG_NET_CLS_CGROUP)	+= cls_cgroup.o
+obj-$(CONFIG_NET_CLS_COUNTER)   += cls_counter_holder.o
 obj-$(CONFIG_NET_EMATCH)	+= ematch.o
 obj-$(CONFIG_NET_EMATCH_CMP)	+= em_cmp.o
 obj-$(CONFIG_NET_EMATCH_NBYTE)	+= em_nbyte.o
net/sched/cls_cgroup.c +191 -3

250 lines not on this page · raw message

net/sched/cls_counter_holder.c new file +144 -0

144 lines not on this page · raw message

Signature · 1 line
1.7.9.5
#1 lore raw
Quoted 16 lines · Alexey Perevalov

Traffic counter based on classification control group

The main goal of this patch it's counting traffic for process placed to net_cls cgroup (ingress and egress).
It's based on atomic and holds counter per network interfaces.

It handles packets in net/core/dev.c for egress and in /net/ipv4/tcp.c|udp.c for ingress.

Cgroup fs interface provides following files additional to existing
net_cls files:
net_cls.ifacename.usage_in_bytes Containing rcv/snd lines.

---

...

Quoted 12 lines

index d1e8116..ffc9ec2 100644

net/core/dev.c +1 -0
@@ -135,6 +135,7 @@
 #include <linux/net_tstamp.h>
 #include <linux/static_key.h>
 #include <net/flow_keys.h>
+#include <net/cls_cgroup.h>
 
 #include "net-sysfs.h"
 

net/core/dev.c int dev_queue_xmit(struct sk_buff *skb) · line 2927

Quoted 5 lines
net/core/dev.c +2 -0
@@ -2922,6 +2923,11 @@ int dev_queue_xmit(struct sk_buff *skb)
 	 */
 	rcu_read_lock_bh();
 
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+	if (dev)

How dev could be NULL here ?

net/core/dev.c int dev_queue_xmit(struct sk_buff *skb) · line 2929

Quoted 2 lines
net/core/dev.c +2 -0
+		count_cls_snd(skb_cls_classid(skb), skb->len, dev->name);
+#endif

Why do you add these ugly ifdefs in the C files ?

As already said, you should not add new ifdef in C files, but properly define empty functions in the header files

#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
...
#else
static inline void count_cls_snd( args ) { }
#endif

Quoted 82 lines
net/core/dev.c +1 -0
+
 	skb_update_prio(skb);
 
 	txq = netdev_pick_tx(dev, skb);
net/ipv4/tcp.c +21 -1
index 1ca2536..dc4dc3a 100644
@@ -276,6 +276,7 @@
 #include <net/ip.h>
 #include <net/netdma.h>
 #include <net/sock.h>
+#include <net/cls_cgroup.h>
 
 #include <asm/uaccess.h>
 #include <asm/ioctls.h>
@@ -1464,6 +1465,9 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
 	u32 seq = tp->copied_seq;
 	u32 offset;
 	int copied = 0;
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+	int ifindex = 0;
+#endif
 
 	if (sk->sk_state == TCP_LISTEN)
 		return -ENOTCONN;
@@ -1510,6 +1514,9 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
 			++seq;
 			break;
 		}
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+		ifindex = get_ifindex_from_skb(skb);
+#endif
 		sk_eat_skb(sk, skb, false);
 		if (!desc->count)
 			break;
@@ -1520,8 +1527,12 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
 	tcp_rcv_space_adjust(sk);
 
 	/* Clean up data we have read: This will do ACK frames. */
-	if (copied > 0)
+	if (copied > 0) {
 		tcp_cleanup_rbuf(sk, copied);
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+		count_cls_rcv(current, copied, ifindex);
+#endif
+	}
 	return copied;
 }
 EXPORT_SYMBOL(tcp_read_sock);
@@ -1549,6 +1560,9 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 	bool copied_early = false;
 	struct sk_buff *skb;
 	u32 urg_hole = 0;
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+	int ifindex = 0;
+#endif
 
 	lock_sock(sk);
 
@@ -1873,6 +1887,9 @@ skip_copy:
 		if (tcp_hdr(skb)->fin)
 			goto found_fin_ok;
 		if (!(flags & MSG_PEEK)) {
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+			ifindex = get_ifindex_from_skb(skb);
+#endif
 			sk_eat_skb(sk, skb, copied_early);
 			copied_early = false;
 		}
@@ -1882,6 +1899,9 @@ skip_copy:
 		/* Process the FIN. */
 		++*seq;
 		if (!(flags & MSG_PEEK)) {
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+			ifindex = get_ifindex_from_skb(skb);
+#endif
 			sk_eat_skb(sk, skb, copied_early);
 			copied_early = false;
 		}
@@ -1924,6 +1944,11 @@ skip_copy:
 	/* Clean up data we have read: This will do ACK frames. */

net/ipv4/tcp.c skip_copy: · line 1954

Quoted 10 lines
net/ipv4/tcp.c +5 -0
 	tcp_cleanup_rbuf(sk, copied);
 
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+	if (copied > 0)
+		count_cls_rcv(current, copied, ifindex);
+#endif
+
 	release_sock(sk);
 	return copied;
 

There is no need to add so much ugly code in tcp at least

For input packets, as soon as we identify a matching socket in IP/TCP early demux, we are done. It permits to properly account packets, even the retransmits and ACKS, and even packets dropped by netfilter or sk_filter.