mirror of https://gitee.com/openkylin/linux.git
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:
parent
24ea591d22
commit
519c818e8f
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue