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: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: John Hurley <john.hurley@netronome.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Jakub Kicinski 2018-11-19 15:21:43 -08:00 committed by David S. Miller
parent 890d8d23ec
commit e49efd5288
2 changed files with 55 additions and 0 deletions

View File

@ -871,6 +871,7 @@ struct tc_red_qopt_offload {
enum tc_gred_command {
TC_GRED_REPLACE,
TC_GRED_DESTROY,
TC_GRED_STATS,
};
struct tc_gred_vq_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_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 {
enum tc_gred_command command;
u32 handle;
u32 parent;
union {
struct tc_gred_qopt_offload_params set;
struct tc_gred_qopt_offload_stats stats;
};
};

View File

@ -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);
}
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)
{
kfree(q);
@ -725,6 +769,9 @@ static int gred_dump(struct Qdisc *sch, struct sk_buff *skb)
.flags = table->red_flags,
};
if (gred_offload_dump_stats(sch))
goto nla_put_failure;
opts = nla_nest_start(skb, TCA_OPTIONS);
if (opts == NULL)
goto nla_put_failure;