cgroup: net_cls: traffic counter based on classification control cgroup
Subsystems (6)
RFC PATCH v3 1/1 cgroup: net_cls: traffic counter based on classification control cgroup
Hello
I would like to represent next version of patch I sent before
cgroup: "net_cls: traffic counter based on classification control cgroup"
The main idea is the same as was. It keeping counter in control groups, but now uses atomic instead of resource_counters.
--- 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 +++++++++++++++++++++++++++ 12 files changed, 611 insertions(+), 35 deletions(-) create mode 100644 include/net/cls_counter_holder.h create mode 100644 net/sched/cls_counter_holder.c
include/net/cls_cgroup.h +180 -20
@@ -13,54 +13,197 @@#ifndef _NET_CLS_CGROUP_H#define _NET_CLS_CGROUP_H +#include <linux/atomic.h> #include <linux/cgroup.h> #include <linux/hardirq.h> #include <linux/rcupdate.h> +#if IS_ENABLED (CONFIG_NET_CLS_COUNTER ) +#include <linux/nsproxy.h> +#include <linux/string.h> +#include <linux/skbuff.h> +#include <net/cls_counter_holder.h> +#include <net/sock.h> + +/*TODO hide all it to separate file*/ + +struct cls_iface_cntrs { +char *dev_name; +atomic64_t snd_counter; +atomic64_t rcv_counter; +struct list_head link; +}; + +#endif /*CONFIG_NET_CLS_COUNTER*/ + +#if IS_ENABLED (CONFIG_NET_CLS_CGROUP )struct cgroup_cls_state {struct cgroup_subsys_state css;u32 classid; +#if IS_ENABLED (CONFIG_NET_CLS_COUNTER ) +struct cls_iface_cntrs iface_stats; +#endif /*CONFIG_NET_CLS_COUNTER*/ };extern void sock_update_classid (struct sock *sk,struct task_struct *task); -#if IS_BUILTIN (CONFIG_NET_CLS_CGROUP ) -static inline u32 task_cls_classid (struct task_struct *p) +#if IS_MODULE (CONFIG_NET_CLS_CGROUP ) +static inline struct cgroup_cls_state *get_cls_cgroup (struct task_struct *p) { -u32 classid; +struct cgroup_subsys_state *css =task_subsys_state (p, + net_cls_subsys_id); +if (css) +return container_of (css, + struct cgroup_cls_state, css); +return NULL ; +} +#elif IS_BUILTIN (CONFIG_NET_CLS_CGROUP ) +static inline struct cgroup_cls_state *get_cls_cgroup (struct task_struct *p) +{ +return container_of (task_subsys_state (p, net_cls_subsys_id), + struct cgroup_cls_state, css); +} +#endif -if (in_interrupt ()) -return 0 ; -rcu_read_lock (); - classid =container_of (task_subsys_state (p, net_cls_subsys_id), - struct cgroup_cls_state, css)->classid; -rcu_read_unlock (); +#endif /*CONFIG_NET_CLS_CGROUP*/ -return classid; +#if IS_ENABLED (CONFIG_NET_CLS_CGROUP ) +#if IS_ENABLED (CONFIG_NET_CLS_COUNTER ) +static inline u32 skb_cls_classid (const struct sk_buff *skb) +{ +return (skb && skb->sk) ? skb->sk->sk_classid :0 ; +} + +static inline int get_ifindex_from_skb (const struct sk_buff *skb) +{ +int ifindex =0 ; +if (skb) + ifindex = skb->skb_iif; +return ifindex; +} + +static struct cls_iface_cntrs *find_cls_counter ( +struct cgroup_cls_state *cls_cgroup, +const char *dev_name, +bool create) +{ +/*TODO Add lock*/ +struct cls_iface_cntrs *entry =NULL ; + +if (!dev_name) { +pr_err ("cls please provide valid dev name" ); +return NULL ; + } + +list_for_each_entry (entry, &cls_cgroup->iface_stats.link, link) +if (!strcmp (entry->dev_name, dev_name)) +return entry; + +if (!create) +return entry; + +/*not found, insert*/ + entry =kmalloc (sizeof (struct cls_iface_cntrs ),GFP_ATOMIC ); + entry->dev_name =kstrdup (dev_name,GFP_ATOMIC ); +atomic64_set (&entry->rcv_counter,0 ); +atomic64_set (&entry->snd_counter,0 ); +list_add_tail (&entry->link, &cls_cgroup->iface_stats.link); +return entry; } -#elif IS_MODULE (CONFIG_NET_CLS_CGROUP ) + +static void charge_net_cls_snd (struct cgroup_cls_state *cls_cgroup, +const u32 copied,const char *dev_name) +{ +struct cls_iface_cntrs *cnt =find_cls_counter (cls_cgroup, + dev_name, true); + +if (!cnt) +return ; + +atomic64_add (copied, &cnt->snd_counter); +} + +static char *get_dev_name (const int ifindex) +{ +struct net *net =NULL ; +struct nsproxy *nsproxy =NULL ; +struct net_device *net_dev =NULL ; + + nsproxy =task_nsproxy (current); +if (!nsproxy) { +pr_debug ("cls cant find task_nsproxy" ); +return NULL ; + } + + net =get_net (nsproxy->net_ns); +if (!net) { +pr_debug ("cls cant find net" ); +return NULL ; + } + net_dev =dev_get_by_index (net, ifindex); + +return net_dev ? net_dev->name :NULL ; +} + +static void charge_net_cls_rcv (struct cgroup_cls_state *cls_cgroup, +const u32 copied,const int ifindex) +{ +char *dev_name =get_dev_name (ifindex); +struct cls_iface_cntrs *cnt =find_cls_counter (cls_cgroup, + dev_name, true); + +if (!cnt) +return ; + +atomic64_add (copied, &cnt->rcv_counter); +} + +static inline void count_cls_rcv (struct task_struct *p,const u32 copied, +const int ifindex) +{ +struct cgroup_cls_state *cls_cgroup; + + cls_cgroup =get_cls_cgroup (p); + +if (cls_cgroup) +charge_net_cls_rcv (cls_cgroup, copied, ifindex); +} + +static inline void count_cls_snd (u32 classid,const u32 copied, +const char *dev_name) +{ +struct cgroup_cls_state *cls_cgroup; + + cls_cgroup =find_cls_cgroup_by_classid (classid); + +if (cls_cgroup) +charge_net_cls_snd (cls_cgroup, copied, dev_name); +} +#endif /*CONFIG_NET_CLS_COUNTER*/ +static inline u32 task_cls_classid (struct task_struct *p) { -struct cgroup_subsys_state *css; -u32 classid =0 ; +int classid =0 ; +struct cgroup_cls_state *cls_cgroup =NULL ;if (in_interrupt ())return 0 ;rcu_read_lock (); - css =task_subsys_state (p, net_cls_subsys_id); -if (css) - classid =container_of (css, - struct cgroup_cls_state, css)->classid; + + cls_cgroup =get_cls_cgroup (p); +if (cls_cgroup) + classid = cls_cgroup->classid; +rcu_read_unlock ();return classid; } -#endif -#else /* !CGROUP_NET_CLS_CGROUP */ + +#else /* !CONFIG_NET_CLS_CGROUP */ static inline void sock_update_classid (struct sock *sk,struct task_struct *task) { }
@@ -69,5 +212,22 @@ static inline u32 task_cls_classid(struct task_struct *p) {return 0 ; } -#endif /* CGROUP_NET_CLS_CGROUP */ +#endif /* CONFIG_NET_CLS_CGROUP */ + +#if !IS_ENABLED (CONFIG_NET_CLS_CGROUP ) || !IS_ENABLED (CONFIG_NET_CLS_COUNTER ) +static inline void count_cls_rcv (struct task_struct *p,const u32 copied, +const int ifindex) +{ +} + +static inline void count_cls_snd (u32 classid,const u32 copied, +const char *dev_name) +{ +} + +static inline u32 skb_cls_classid (const struct sk_buff *skb) +{ +return 0 ; +} +#endif #endif /* _NET_CLS_CGROUP_H */
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 8 lines · Alexey Perevalov
Hello
I would like to represent next version of patch I sent before
cgroup: "net_cls: traffic counter based on classification control cgroup"The main idea is the same as was. It keeping counter in control groups, but now uses atomic instead of
resource_counters.Signed-off-by Alexey Perevalov <[email protected]>
Quoted 16 lines
--- 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 +++++++++++++++++++++++++++ 12 files changed, 611 insertions(+), 35 deletions(-) create mode 100644 include/net/cls_counter_holder.h create mode 100644 net/sched/cls_counter_holder.c
Sorry, there are too many issues with this patch and I have not a lot of time to review it.
0) No changelog or documentation
1) There is no way you need to add kludges in tcp and udp for this accounting. Retransmitted packets should not be ignored for example.
2) Ugly #ifdef in c files. Don't do that please.
3) No check of kmalloc() returns (can be NULL)
Hello Eric
Quoted 25 lines · Eric Dumazet
Quoted 22 lines · Alexey Perevalov
Hello
I would like to represent next version of patch I sent before
cgroup: "net_cls: traffic counter based on classification control cgroup"The main idea is the same as was. It keeping counter in control groups, but now uses atomic instead of
resource_counters.Signed-off-by Alexey Perevalov<[email protected]>--- 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 +++++++++++++++++++++++++++ 12 files changed, 611 insertions(+), 35 deletions(-)Quoted 2 lines
create mode 100644
include/net/cls_counter_holder.hcreate mode 100644net/sched/cls_counter_holder.c
Quoted 4 lines
Sorry, there are too many issues with this patch and I have not a lot of time to review it.
0) No changelog or documentation
Do you expect documentation in Documentation/cgroups/. For example I'll create new file net_cls.txt
Quoted 2 lines
1) There is no way you need to add kludges in tcp and udp for this accounting. Retransmitted packets should not be ignored for example.
Retransmitted incoming packets will be ignored - right.
But counting on the 3rd layer of network stack (in netfilter) is expensive, we should twice resolve destination process.
Quoted 4 lines
2) Ugly #ifdef in c files. Don't do that please.
3) No check of
kmalloc()returns (can be NULL)
This issues I'll fix.
Quoted 1 line
Signature · 2 lines
Best regards, Alexey Perevalov