Commit e49efd52 authored by Jakub Kicinski's avatar Jakub Kicinski Committed by David S. Miller

net: sched: gred: support reporting stats from offloads

Allow drivers which offload GRED to report back statistics.  Since
A lot of GRED stats is fairly ad hoc in nature pass to drivers the
standard struct gnet_stats_basic/gnet_stats_queue pairs, and
untangle the values in the core.
Signed-off-by: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: default avatarJohn Hurley <john.hurley@netronome.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 890d8d23
...@@ -871,6 +871,7 @@ struct tc_red_qopt_offload { ...@@ -871,6 +871,7 @@ struct tc_red_qopt_offload {
enum tc_gred_command { enum tc_gred_command {
TC_GRED_REPLACE, TC_GRED_REPLACE,
TC_GRED_DESTROY, TC_GRED_DESTROY,
TC_GRED_STATS,
}; };
struct tc_gred_vq_qopt_offload_params { struct tc_gred_vq_qopt_offload_params {
...@@ -895,12 +896,19 @@ struct tc_gred_qopt_offload_params { ...@@ -895,12 +896,19 @@ struct tc_gred_qopt_offload_params {
struct tc_gred_vq_qopt_offload_params tab[MAX_DPs]; struct tc_gred_vq_qopt_offload_params tab[MAX_DPs];
}; };
struct tc_gred_qopt_offload_stats {
struct gnet_stats_basic_packed bstats[MAX_DPs];
struct gnet_stats_queue qstats[MAX_DPs];
struct red_stats *xstats[MAX_DPs];
};
struct tc_gred_qopt_offload { struct tc_gred_qopt_offload {
enum tc_gred_command command; enum tc_gred_command command;
u32 handle; u32 handle;
u32 parent; u32 parent;
union { union {
struct tc_gred_qopt_offload_params set; struct tc_gred_qopt_offload_params set;
struct tc_gred_qopt_offload_stats stats;
}; };
}; };
......
...@@ -354,6 +354,50 @@ static void gred_offload(struct Qdisc *sch, enum tc_gred_command command) ...@@ -354,6 +354,50 @@ static void gred_offload(struct Qdisc *sch, enum tc_gred_command command)
dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_GRED, &opt); dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_GRED, &opt);
} }
static int gred_offload_dump_stats(struct Qdisc *sch)
{
struct gred_sched *table = qdisc_priv(sch);
struct tc_gred_qopt_offload *hw_stats;
unsigned int i;
int ret;
hw_stats = kzalloc(sizeof(*hw_stats), GFP_KERNEL);
if (!hw_stats)
return -ENOMEM;
hw_stats->command = TC_GRED_STATS;
hw_stats->handle = sch->handle;
hw_stats->parent = sch->parent;
for (i = 0; i < MAX_DPs; i++)
if (table->tab[i])
hw_stats->stats.xstats[i] = &table->tab[i]->stats;
ret = qdisc_offload_dump_helper(sch, TC_SETUP_QDISC_GRED, hw_stats);
/* Even if driver returns failure adjust the stats - in case offload
* ended but driver still wants to adjust the values.
*/
for (i = 0; i < MAX_DPs; i++) {
if (!table->tab[i])
continue;
table->tab[i]->packetsin += hw_stats->stats.bstats[i].packets;
table->tab[i]->bytesin += hw_stats->stats.bstats[i].bytes;
table->tab[i]->backlog += hw_stats->stats.qstats[i].backlog;
_bstats_update(&sch->bstats,
hw_stats->stats.bstats[i].bytes,
hw_stats->stats.bstats[i].packets);
sch->qstats.qlen += hw_stats->stats.qstats[i].qlen;
sch->qstats.backlog += hw_stats->stats.qstats[i].backlog;
sch->qstats.drops += hw_stats->stats.qstats[i].drops;
sch->qstats.requeues += hw_stats->stats.qstats[i].requeues;
sch->qstats.overlimits += hw_stats->stats.qstats[i].overlimits;
}
kfree(hw_stats);
return ret;
}
static inline void gred_destroy_vq(struct gred_sched_data *q) static inline void gred_destroy_vq(struct gred_sched_data *q)
{ {
kfree(q); kfree(q);
...@@ -725,6 +769,9 @@ static int gred_dump(struct Qdisc *sch, struct sk_buff *skb) ...@@ -725,6 +769,9 @@ static int gred_dump(struct Qdisc *sch, struct sk_buff *skb)
.flags = table->red_flags, .flags = table->red_flags,
}; };
if (gred_offload_dump_stats(sch))
goto nla_put_failure;
opts = nla_nest_start(skb, TCA_OPTIONS); opts = nla_nest_start(skb, TCA_OPTIONS);
if (opts == NULL) if (opts == NULL)
goto nla_put_failure; goto nla_put_failure;
......
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