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:
Родитель
890d8d23ec
Коммит
e49efd5288
|
@ -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;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче