cgroup: net_cls: traffic counter based on classification control cgroup
Subsystems (7)
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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
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_clscgroup (ingress and egress).
It's based on atomic and holds counter per network interfaces.It handles packets in
net/core/dev.cfor egress and in /net/ipv4/tcp.c|udp.c for ingress.Cgroup fs interface provides following files additional to existing
net_clsfiles:
net_cls.ifacename.usage_in_bytes Containing rcv/snd lines.Signed-off-by Alexey Perevalov <[email protected]>---
...
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@@ -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
-0tcp_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.