Commit ea49c6f0 authored by David S. Miller's avatar David S. Miller

Merge branch 'net-sched-Add-hardware-specific-counters-to-TC-actions'

Eelco Chaudron says:

====================
net/sched: Add hardware specific counters to TC actions

Add hardware specific counters to TC actions which will be exported
through the netlink API. This makes troubleshooting TC flower offload
easier, as it possible to differentiate the packets being offloaded.

v2 - Rebased on latest net-next
====================
Signed-off-by: default avatarEelco Chaudron <echaudro@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 7ff2ea0b 28169aba
...@@ -31,10 +31,12 @@ struct tc_action { ...@@ -31,10 +31,12 @@ struct tc_action {
int tcfa_action; int tcfa_action;
struct tcf_t tcfa_tm; struct tcf_t tcfa_tm;
struct gnet_stats_basic_packed tcfa_bstats; struct gnet_stats_basic_packed tcfa_bstats;
struct gnet_stats_basic_packed tcfa_bstats_hw;
struct gnet_stats_queue tcfa_qstats; struct gnet_stats_queue tcfa_qstats;
struct net_rate_estimator __rcu *tcfa_rate_est; struct net_rate_estimator __rcu *tcfa_rate_est;
spinlock_t tcfa_lock; spinlock_t tcfa_lock;
struct gnet_stats_basic_cpu __percpu *cpu_bstats; struct gnet_stats_basic_cpu __percpu *cpu_bstats;
struct gnet_stats_basic_cpu __percpu *cpu_bstats_hw;
struct gnet_stats_queue __percpu *cpu_qstats; struct gnet_stats_queue __percpu *cpu_qstats;
struct tc_cookie __rcu *act_cookie; struct tc_cookie __rcu *act_cookie;
struct tcf_chain *goto_chain; struct tcf_chain *goto_chain;
...@@ -94,7 +96,7 @@ struct tc_action_ops { ...@@ -94,7 +96,7 @@ struct tc_action_ops {
struct netlink_callback *, int, struct netlink_callback *, int,
const struct tc_action_ops *, const struct tc_action_ops *,
struct netlink_ext_ack *); struct netlink_ext_ack *);
void (*stats_update)(struct tc_action *, u64, u32, u64); void (*stats_update)(struct tc_action *, u64, u32, u64, bool);
size_t (*get_fill_size)(const struct tc_action *act); size_t (*get_fill_size)(const struct tc_action *act);
struct net_device *(*get_dev)(const struct tc_action *a); struct net_device *(*get_dev)(const struct tc_action *a);
void (*put_dev)(struct net_device *dev); void (*put_dev)(struct net_device *dev);
...@@ -182,13 +184,13 @@ int tcf_action_copy_stats(struct sk_buff *, struct tc_action *, int); ...@@ -182,13 +184,13 @@ int tcf_action_copy_stats(struct sk_buff *, struct tc_action *, int);
#endif /* CONFIG_NET_CLS_ACT */ #endif /* CONFIG_NET_CLS_ACT */
static inline void tcf_action_stats_update(struct tc_action *a, u64 bytes, static inline void tcf_action_stats_update(struct tc_action *a, u64 bytes,
u64 packets, u64 lastuse) u64 packets, u64 lastuse, bool hw)
{ {
#ifdef CONFIG_NET_CLS_ACT #ifdef CONFIG_NET_CLS_ACT
if (!a->ops->stats_update) if (!a->ops->stats_update)
return; return;
a->ops->stats_update(a, bytes, packets, lastuse); a->ops->stats_update(a, bytes, packets, lastuse, hw);
#endif #endif
} }
......
...@@ -44,6 +44,10 @@ void __gnet_stats_copy_basic(const seqcount_t *running, ...@@ -44,6 +44,10 @@ void __gnet_stats_copy_basic(const seqcount_t *running,
struct gnet_stats_basic_packed *bstats, struct gnet_stats_basic_packed *bstats,
struct gnet_stats_basic_cpu __percpu *cpu, struct gnet_stats_basic_cpu __percpu *cpu,
struct gnet_stats_basic_packed *b); struct gnet_stats_basic_packed *b);
int gnet_stats_copy_basic_hw(const seqcount_t *running,
struct gnet_dump *d,
struct gnet_stats_basic_cpu __percpu *cpu,
struct gnet_stats_basic_packed *b);
int gnet_stats_copy_rate_est(struct gnet_dump *d, int gnet_stats_copy_rate_est(struct gnet_dump *d,
struct net_rate_estimator __rcu **ptr); struct net_rate_estimator __rcu **ptr);
int gnet_stats_copy_queue(struct gnet_dump *d, int gnet_stats_copy_queue(struct gnet_dump *d,
......
...@@ -318,7 +318,7 @@ tcf_exts_stats_update(const struct tcf_exts *exts, ...@@ -318,7 +318,7 @@ tcf_exts_stats_update(const struct tcf_exts *exts,
for (i = 0; i < exts->nr_actions; i++) { for (i = 0; i < exts->nr_actions; i++) {
struct tc_action *a = exts->actions[i]; struct tc_action *a = exts->actions[i];
tcf_action_stats_update(a, bytes, packets, lastuse); tcf_action_stats_update(a, bytes, packets, lastuse, true);
} }
preempt_enable(); preempt_enable();
......
...@@ -12,6 +12,7 @@ enum { ...@@ -12,6 +12,7 @@ enum {
TCA_STATS_APP, TCA_STATS_APP,
TCA_STATS_RATE_EST64, TCA_STATS_RATE_EST64,
TCA_STATS_PAD, TCA_STATS_PAD,
TCA_STATS_BASIC_HW,
__TCA_STATS_MAX, __TCA_STATS_MAX,
}; };
#define TCA_STATS_MAX (__TCA_STATS_MAX - 1) #define TCA_STATS_MAX (__TCA_STATS_MAX - 1)
......
...@@ -162,30 +162,18 @@ __gnet_stats_copy_basic(const seqcount_t *running, ...@@ -162,30 +162,18 @@ __gnet_stats_copy_basic(const seqcount_t *running,
} }
EXPORT_SYMBOL(__gnet_stats_copy_basic); EXPORT_SYMBOL(__gnet_stats_copy_basic);
/**
* gnet_stats_copy_basic - copy basic statistics into statistic TLV
* @running: seqcount_t pointer
* @d: dumping handle
* @cpu: copy statistic per cpu
* @b: basic statistics
*
* Appends the basic statistics to the top level TLV created by
* gnet_stats_start_copy().
*
* Returns 0 on success or -1 with the statistic lock released
* if the room in the socket buffer was not sufficient.
*/
int int
gnet_stats_copy_basic(const seqcount_t *running, ___gnet_stats_copy_basic(const seqcount_t *running,
struct gnet_dump *d, struct gnet_dump *d,
struct gnet_stats_basic_cpu __percpu *cpu, struct gnet_stats_basic_cpu __percpu *cpu,
struct gnet_stats_basic_packed *b) struct gnet_stats_basic_packed *b,
int type)
{ {
struct gnet_stats_basic_packed bstats = {0}; struct gnet_stats_basic_packed bstats = {0};
__gnet_stats_copy_basic(running, &bstats, cpu, b); __gnet_stats_copy_basic(running, &bstats, cpu, b);
if (d->compat_tc_stats) { if (d->compat_tc_stats && type == TCA_STATS_BASIC) {
d->tc_stats.bytes = bstats.bytes; d->tc_stats.bytes = bstats.bytes;
d->tc_stats.packets = bstats.packets; d->tc_stats.packets = bstats.packets;
} }
...@@ -196,13 +184,60 @@ gnet_stats_copy_basic(const seqcount_t *running, ...@@ -196,13 +184,60 @@ gnet_stats_copy_basic(const seqcount_t *running,
memset(&sb, 0, sizeof(sb)); memset(&sb, 0, sizeof(sb));
sb.bytes = bstats.bytes; sb.bytes = bstats.bytes;
sb.packets = bstats.packets; sb.packets = bstats.packets;
return gnet_stats_copy(d, TCA_STATS_BASIC, &sb, sizeof(sb), return gnet_stats_copy(d, type, &sb, sizeof(sb),
TCA_STATS_PAD); TCA_STATS_PAD);
} }
return 0; return 0;
} }
/**
* gnet_stats_copy_basic - copy basic statistics into statistic TLV
* @running: seqcount_t pointer
* @d: dumping handle
* @cpu: copy statistic per cpu
* @b: basic statistics
*
* Appends the basic statistics to the top level TLV created by
* gnet_stats_start_copy().
*
* Returns 0 on success or -1 with the statistic lock released
* if the room in the socket buffer was not sufficient.
*/
int
gnet_stats_copy_basic(const seqcount_t *running,
struct gnet_dump *d,
struct gnet_stats_basic_cpu __percpu *cpu,
struct gnet_stats_basic_packed *b)
{
return ___gnet_stats_copy_basic(running, d, cpu, b,
TCA_STATS_BASIC);
}
EXPORT_SYMBOL(gnet_stats_copy_basic); EXPORT_SYMBOL(gnet_stats_copy_basic);
/**
* gnet_stats_copy_basic_hw - copy basic hw statistics into statistic TLV
* @running: seqcount_t pointer
* @d: dumping handle
* @cpu: copy statistic per cpu
* @b: basic statistics
*
* Appends the basic statistics to the top level TLV created by
* gnet_stats_start_copy().
*
* Returns 0 on success or -1 with the statistic lock released
* if the room in the socket buffer was not sufficient.
*/
int
gnet_stats_copy_basic_hw(const seqcount_t *running,
struct gnet_dump *d,
struct gnet_stats_basic_cpu __percpu *cpu,
struct gnet_stats_basic_packed *b)
{
return ___gnet_stats_copy_basic(running, d, cpu, b,
TCA_STATS_BASIC_HW);
}
EXPORT_SYMBOL(gnet_stats_copy_basic_hw);
/** /**
* gnet_stats_copy_rate_est - copy rate estimator statistics into statistics TLV * gnet_stats_copy_rate_est - copy rate estimator statistics into statistics TLV
* @d: dumping handle * @d: dumping handle
......
...@@ -81,6 +81,7 @@ static void tcf_set_action_cookie(struct tc_cookie __rcu **old_cookie, ...@@ -81,6 +81,7 @@ static void tcf_set_action_cookie(struct tc_cookie __rcu **old_cookie,
static void free_tcf(struct tc_action *p) static void free_tcf(struct tc_action *p)
{ {
free_percpu(p->cpu_bstats); free_percpu(p->cpu_bstats);
free_percpu(p->cpu_bstats_hw);
free_percpu(p->cpu_qstats); free_percpu(p->cpu_qstats);
tcf_set_action_cookie(&p->act_cookie, NULL); tcf_set_action_cookie(&p->act_cookie, NULL);
...@@ -390,9 +391,12 @@ int tcf_idr_create(struct tc_action_net *tn, u32 index, struct nlattr *est, ...@@ -390,9 +391,12 @@ int tcf_idr_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
p->cpu_bstats = netdev_alloc_pcpu_stats(struct gnet_stats_basic_cpu); p->cpu_bstats = netdev_alloc_pcpu_stats(struct gnet_stats_basic_cpu);
if (!p->cpu_bstats) if (!p->cpu_bstats)
goto err1; goto err1;
p->cpu_bstats_hw = netdev_alloc_pcpu_stats(struct gnet_stats_basic_cpu);
if (!p->cpu_bstats_hw)
goto err2;
p->cpu_qstats = alloc_percpu(struct gnet_stats_queue); p->cpu_qstats = alloc_percpu(struct gnet_stats_queue);
if (!p->cpu_qstats) if (!p->cpu_qstats)
goto err2; goto err3;
} }
spin_lock_init(&p->tcfa_lock); spin_lock_init(&p->tcfa_lock);
p->tcfa_index = index; p->tcfa_index = index;
...@@ -404,15 +408,17 @@ int tcf_idr_create(struct tc_action_net *tn, u32 index, struct nlattr *est, ...@@ -404,15 +408,17 @@ int tcf_idr_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
&p->tcfa_rate_est, &p->tcfa_rate_est,
&p->tcfa_lock, NULL, est); &p->tcfa_lock, NULL, est);
if (err) if (err)
goto err3; goto err4;
} }
p->idrinfo = idrinfo; p->idrinfo = idrinfo;
p->ops = ops; p->ops = ops;
*a = p; *a = p;
return 0; return 0;
err3: err4:
free_percpu(p->cpu_qstats); free_percpu(p->cpu_qstats);
err3:
free_percpu(p->cpu_bstats_hw);
err2: err2:
free_percpu(p->cpu_bstats); free_percpu(p->cpu_bstats);
err1: err1:
...@@ -997,6 +1003,8 @@ int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *p, ...@@ -997,6 +1003,8 @@ int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *p,
goto errout; goto errout;
if (gnet_stats_copy_basic(NULL, &d, p->cpu_bstats, &p->tcfa_bstats) < 0 || if (gnet_stats_copy_basic(NULL, &d, p->cpu_bstats, &p->tcfa_bstats) < 0 ||
gnet_stats_copy_basic_hw(NULL, &d, p->cpu_bstats_hw,
&p->tcfa_bstats_hw) < 0 ||
gnet_stats_copy_rate_est(&d, &p->tcfa_rate_est) < 0 || gnet_stats_copy_rate_est(&d, &p->tcfa_rate_est) < 0 ||
gnet_stats_copy_queue(&d, p->cpu_qstats, gnet_stats_copy_queue(&d, p->cpu_qstats,
&p->tcfa_qstats, &p->tcfa_qstats,
......
...@@ -157,7 +157,7 @@ static int tcf_gact_act(struct sk_buff *skb, const struct tc_action *a, ...@@ -157,7 +157,7 @@ static int tcf_gact_act(struct sk_buff *skb, const struct tc_action *a,
} }
static void tcf_gact_stats_update(struct tc_action *a, u64 bytes, u32 packets, static void tcf_gact_stats_update(struct tc_action *a, u64 bytes, u32 packets,
u64 lastuse) u64 lastuse, bool hw)
{ {
struct tcf_gact *gact = to_gact(a); struct tcf_gact *gact = to_gact(a);
int action = READ_ONCE(gact->tcf_action); int action = READ_ONCE(gact->tcf_action);
...@@ -168,6 +168,10 @@ static void tcf_gact_stats_update(struct tc_action *a, u64 bytes, u32 packets, ...@@ -168,6 +168,10 @@ static void tcf_gact_stats_update(struct tc_action *a, u64 bytes, u32 packets,
if (action == TC_ACT_SHOT) if (action == TC_ACT_SHOT)
this_cpu_ptr(gact->common.cpu_qstats)->drops += packets; this_cpu_ptr(gact->common.cpu_qstats)->drops += packets;
if (hw)
_bstats_cpu_update(this_cpu_ptr(gact->common.cpu_bstats_hw),
bytes, packets);
tm->lastuse = max_t(u64, tm->lastuse, lastuse); tm->lastuse = max_t(u64, tm->lastuse, lastuse);
} }
......
...@@ -283,12 +283,15 @@ static int tcf_mirred_act(struct sk_buff *skb, const struct tc_action *a, ...@@ -283,12 +283,15 @@ static int tcf_mirred_act(struct sk_buff *skb, const struct tc_action *a,
} }
static void tcf_stats_update(struct tc_action *a, u64 bytes, u32 packets, static void tcf_stats_update(struct tc_action *a, u64 bytes, u32 packets,
u64 lastuse) u64 lastuse, bool hw)
{ {
struct tcf_mirred *m = to_mirred(a); struct tcf_mirred *m = to_mirred(a);
struct tcf_t *tm = &m->tcf_tm; struct tcf_t *tm = &m->tcf_tm;
_bstats_cpu_update(this_cpu_ptr(a->cpu_bstats), bytes, packets); _bstats_cpu_update(this_cpu_ptr(a->cpu_bstats), bytes, packets);
if (hw)
_bstats_cpu_update(this_cpu_ptr(a->cpu_bstats_hw),
bytes, packets);
tm->lastuse = max_t(u64, tm->lastuse, lastuse); tm->lastuse = max_t(u64, tm->lastuse, lastuse);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment