net: sched: add percpu stats to actions

Reuse existing percpu infrastructure John Fastabend added for qdisc.

This patch adds a new cpustats parameter to tcf_hash_create() and all
actions pass false, meaning this patch should have no effect yet.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Alexei Starovoitov <ast@plumgrid.com>
Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
Acked-by: John Fastabend <john.fastabend@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Eric Dumazet 2015-07-06 05:18:04 -07:00 committed by David S. Miller
parent 24ea591d22
commit 519c818e8f
13 changed files with 57 additions and 22 deletions

View File

@ -21,6 +21,8 @@ struct tcf_common {
struct gnet_stats_rate_est64 tcfc_rate_est; struct gnet_stats_rate_est64 tcfc_rate_est;
spinlock_t tcfc_lock; spinlock_t tcfc_lock;
struct rcu_head tcfc_rcu; struct rcu_head tcfc_rcu;
struct gnet_stats_basic_cpu __percpu *cpu_bstats;
struct gnet_stats_queue __percpu *cpu_qstats;
}; };
#define tcf_head common.tcfc_head #define tcf_head common.tcfc_head
#define tcf_index common.tcfc_index #define tcf_index common.tcfc_index
@ -103,7 +105,7 @@ int tcf_hash_release(struct tc_action *a, int bind);
u32 tcf_hash_new_index(struct tcf_hashinfo *hinfo); u32 tcf_hash_new_index(struct tcf_hashinfo *hinfo);
int tcf_hash_check(u32 index, struct tc_action *a, int bind); int tcf_hash_check(u32 index, struct tc_action *a, int bind);
int tcf_hash_create(u32 index, struct nlattr *est, struct tc_action *a, int tcf_hash_create(u32 index, struct nlattr *est, struct tc_action *a,
int size, int bind); int size, int bind, bool cpustats);
void tcf_hash_cleanup(struct tc_action *a, struct nlattr *est); void tcf_hash_cleanup(struct tc_action *a, struct nlattr *est);
void tcf_hash_insert(struct tc_action *a); void tcf_hash_insert(struct tc_action *a);

View File

@ -27,6 +27,15 @@
#include <net/act_api.h> #include <net/act_api.h>
#include <net/netlink.h> #include <net/netlink.h>
static void free_tcf(struct rcu_head *head)
{
struct tcf_common *p = container_of(head, struct tcf_common, tcfc_rcu);
free_percpu(p->cpu_bstats);
free_percpu(p->cpu_qstats);
kfree(p);
}
void tcf_hash_destroy(struct tc_action *a) void tcf_hash_destroy(struct tc_action *a)
{ {
struct tcf_common *p = a->priv; struct tcf_common *p = a->priv;
@ -41,7 +50,7 @@ void tcf_hash_destroy(struct tc_action *a)
* gen_estimator est_timer() might access p->tcfc_lock * gen_estimator est_timer() might access p->tcfc_lock
* or bstats, wait a RCU grace period before freeing p * or bstats, wait a RCU grace period before freeing p
*/ */
kfree_rcu(p, tcfc_rcu); call_rcu(&p->tcfc_rcu, free_tcf);
} }
EXPORT_SYMBOL(tcf_hash_destroy); EXPORT_SYMBOL(tcf_hash_destroy);
@ -230,15 +239,16 @@ void tcf_hash_cleanup(struct tc_action *a, struct nlattr *est)
if (est) if (est)
gen_kill_estimator(&pc->tcfc_bstats, gen_kill_estimator(&pc->tcfc_bstats,
&pc->tcfc_rate_est); &pc->tcfc_rate_est);
kfree_rcu(pc, tcfc_rcu); call_rcu(&pc->tcfc_rcu, free_tcf);
} }
EXPORT_SYMBOL(tcf_hash_cleanup); EXPORT_SYMBOL(tcf_hash_cleanup);
int tcf_hash_create(u32 index, struct nlattr *est, struct tc_action *a, int tcf_hash_create(u32 index, struct nlattr *est, struct tc_action *a,
int size, int bind) int size, int bind, bool cpustats)
{ {
struct tcf_hashinfo *hinfo = a->ops->hinfo; struct tcf_hashinfo *hinfo = a->ops->hinfo;
struct tcf_common *p = kzalloc(size, GFP_KERNEL); struct tcf_common *p = kzalloc(size, GFP_KERNEL);
int err = -ENOMEM;
if (unlikely(!p)) if (unlikely(!p))
return -ENOMEM; return -ENOMEM;
@ -246,18 +256,32 @@ int tcf_hash_create(u32 index, struct nlattr *est, struct tc_action *a,
if (bind) if (bind)
p->tcfc_bindcnt = 1; p->tcfc_bindcnt = 1;
if (cpustats) {
p->cpu_bstats = netdev_alloc_pcpu_stats(struct gnet_stats_basic_cpu);
if (!p->cpu_bstats) {
err1:
kfree(p);
return err;
}
p->cpu_qstats = alloc_percpu(struct gnet_stats_queue);
if (!p->cpu_qstats) {
err2:
free_percpu(p->cpu_bstats);
goto err1;
}
}
spin_lock_init(&p->tcfc_lock); spin_lock_init(&p->tcfc_lock);
INIT_HLIST_NODE(&p->tcfc_head); INIT_HLIST_NODE(&p->tcfc_head);
p->tcfc_index = index ? index : tcf_hash_new_index(hinfo); p->tcfc_index = index ? index : tcf_hash_new_index(hinfo);
p->tcfc_tm.install = jiffies; p->tcfc_tm.install = jiffies;
p->tcfc_tm.lastuse = jiffies; p->tcfc_tm.lastuse = jiffies;
if (est) { if (est) {
int err = gen_new_estimator(&p->tcfc_bstats, NULL, err = gen_new_estimator(&p->tcfc_bstats, p->cpu_bstats,
&p->tcfc_rate_est, &p->tcfc_rate_est,
&p->tcfc_lock, est); &p->tcfc_lock, est);
if (err) { if (err) {
kfree(p); free_percpu(p->cpu_qstats);
return err; goto err2;
} }
} }
@ -615,10 +639,10 @@ int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a,
if (err < 0) if (err < 0)
goto errout; goto errout;
if (gnet_stats_copy_basic(&d, NULL, &p->tcfc_bstats) < 0 || if (gnet_stats_copy_basic(&d, p->cpu_bstats, &p->tcfc_bstats) < 0 ||
gnet_stats_copy_rate_est(&d, &p->tcfc_bstats, gnet_stats_copy_rate_est(&d, &p->tcfc_bstats,
&p->tcfc_rate_est) < 0 || &p->tcfc_rate_est) < 0 ||
gnet_stats_copy_queue(&d, NULL, gnet_stats_copy_queue(&d, p->cpu_qstats,
&p->tcfc_qstats, &p->tcfc_qstats,
p->tcfc_qstats.qlen) < 0) p->tcfc_qstats.qlen) < 0)
goto errout; goto errout;

View File

@ -281,7 +281,7 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,
if (!tcf_hash_check(parm->index, act, bind)) { if (!tcf_hash_check(parm->index, act, bind)) {
ret = tcf_hash_create(parm->index, est, act, ret = tcf_hash_create(parm->index, est, act,
sizeof(*prog), bind); sizeof(*prog), bind, false);
if (ret < 0) if (ret < 0)
goto destroy_fp; goto destroy_fp;

View File

@ -108,7 +108,8 @@ static int tcf_connmark_init(struct net *net, struct nlattr *nla,
parm = nla_data(tb[TCA_CONNMARK_PARMS]); parm = nla_data(tb[TCA_CONNMARK_PARMS]);
if (!tcf_hash_check(parm->index, a, bind)) { if (!tcf_hash_check(parm->index, a, bind)) {
ret = tcf_hash_create(parm->index, est, a, sizeof(*ci), bind); ret = tcf_hash_create(parm->index, est, a, sizeof(*ci),
bind, false);
if (ret) if (ret)
return ret; return ret;

View File

@ -62,7 +62,8 @@ static int tcf_csum_init(struct net *n, struct nlattr *nla, struct nlattr *est,
parm = nla_data(tb[TCA_CSUM_PARMS]); parm = nla_data(tb[TCA_CSUM_PARMS]);
if (!tcf_hash_check(parm->index, a, bind)) { if (!tcf_hash_check(parm->index, a, bind)) {
ret = tcf_hash_create(parm->index, est, a, sizeof(*p), bind); ret = tcf_hash_create(parm->index, est, a, sizeof(*p),
bind, false);
if (ret) if (ret)
return ret; return ret;
ret = ACT_P_CREATED; ret = ACT_P_CREATED;

View File

@ -85,7 +85,8 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla,
#endif #endif
if (!tcf_hash_check(parm->index, a, bind)) { if (!tcf_hash_check(parm->index, a, bind)) {
ret = tcf_hash_create(parm->index, est, a, sizeof(*gact), bind); ret = tcf_hash_create(parm->index, est, a, sizeof(*gact),
bind, false);
if (ret) if (ret)
return ret; return ret;
ret = ACT_P_CREATED; ret = ACT_P_CREATED;

View File

@ -114,7 +114,7 @@ static int tcf_ipt_init(struct net *net, struct nlattr *nla, struct nlattr *est,
index = nla_get_u32(tb[TCA_IPT_INDEX]); index = nla_get_u32(tb[TCA_IPT_INDEX]);
if (!tcf_hash_check(index, a, bind) ) { if (!tcf_hash_check(index, a, bind) ) {
ret = tcf_hash_create(index, est, a, sizeof(*ipt), bind); ret = tcf_hash_create(index, est, a, sizeof(*ipt), bind, false);
if (ret) if (ret)
return ret; return ret;
ret = ACT_P_CREATED; ret = ACT_P_CREATED;

View File

@ -93,7 +93,8 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
if (!tcf_hash_check(parm->index, a, bind)) { if (!tcf_hash_check(parm->index, a, bind)) {
if (dev == NULL) if (dev == NULL)
return -EINVAL; return -EINVAL;
ret = tcf_hash_create(parm->index, est, a, sizeof(*m), bind); ret = tcf_hash_create(parm->index, est, a, sizeof(*m),
bind, false);
if (ret) if (ret)
return ret; return ret;
ret = ACT_P_CREATED; ret = ACT_P_CREATED;

View File

@ -55,7 +55,8 @@ static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est,
parm = nla_data(tb[TCA_NAT_PARMS]); parm = nla_data(tb[TCA_NAT_PARMS]);
if (!tcf_hash_check(parm->index, a, bind)) { if (!tcf_hash_check(parm->index, a, bind)) {
ret = tcf_hash_create(parm->index, est, a, sizeof(*p), bind); ret = tcf_hash_create(parm->index, est, a, sizeof(*p),
bind, false);
if (ret) if (ret)
return ret; return ret;
ret = ACT_P_CREATED; ret = ACT_P_CREATED;

View File

@ -57,7 +57,8 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
if (!tcf_hash_check(parm->index, a, bind)) { if (!tcf_hash_check(parm->index, a, bind)) {
if (!parm->nkeys) if (!parm->nkeys)
return -EINVAL; return -EINVAL;
ret = tcf_hash_create(parm->index, est, a, sizeof(*p), bind); ret = tcf_hash_create(parm->index, est, a, sizeof(*p),
bind, false);
if (ret) if (ret)
return ret; return ret;
p = to_pedit(a); p = to_pedit(a);

View File

@ -103,7 +103,8 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla,
defdata = nla_data(tb[TCA_DEF_DATA]); defdata = nla_data(tb[TCA_DEF_DATA]);
if (!tcf_hash_check(parm->index, a, bind)) { if (!tcf_hash_check(parm->index, a, bind)) {
ret = tcf_hash_create(parm->index, est, a, sizeof(*d), bind); ret = tcf_hash_create(parm->index, est, a, sizeof(*d),
bind, false);
if (ret) if (ret)
return ret; return ret;

View File

@ -99,7 +99,8 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
parm = nla_data(tb[TCA_SKBEDIT_PARMS]); parm = nla_data(tb[TCA_SKBEDIT_PARMS]);
if (!tcf_hash_check(parm->index, a, bind)) { if (!tcf_hash_check(parm->index, a, bind)) {
ret = tcf_hash_create(parm->index, est, a, sizeof(*d), bind); ret = tcf_hash_create(parm->index, est, a, sizeof(*d),
bind, false);
if (ret) if (ret)
return ret; return ret;

View File

@ -116,7 +116,8 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
action = parm->v_action; action = parm->v_action;
if (!tcf_hash_check(parm->index, a, bind)) { if (!tcf_hash_check(parm->index, a, bind)) {
ret = tcf_hash_create(parm->index, est, a, sizeof(*v), bind); ret = tcf_hash_create(parm->index, est, a, sizeof(*v),
bind, false);
if (ret) if (ret)
return ret; return ret;