* [PATCH net-next 07/14] net: sched: gred: support reporting stats from offloads
From: Jakub Kicinski @ 2018-11-19 23:21 UTC (permalink / raw)
To: davem; +Cc: oss-drivers, netdev, Jakub Kicinski
In-Reply-To: <20181119232150.13038-1-jakub.kicinski@netronome.com>
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>
---
include/net/pkt_cls.h | 8 ++++++++
net/sched/sch_gred.c | 47 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 55 insertions(+)
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index c9198797aaed..d0e9a8091426 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -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;
};
};
diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c
index 908c9d1dfdf8..234afbf9115b 100644
--- a/net/sched/sch_gred.c
+++ b/net/sched/sch_gred.c
@@ -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;
--
2.17.1
^ permalink raw reply related
* [PATCH net-next 08/14] nfp: abm: wrap RED parameters in bands
From: Jakub Kicinski @ 2018-11-19 23:21 UTC (permalink / raw)
To: davem; +Cc: oss-drivers, netdev, Jakub Kicinski
In-Reply-To: <20181119232150.13038-1-jakub.kicinski@netronome.com>
Wrap RED parameters and stats into a structure, and a 1-element
array. Upcoming GRED offload will add the support for more bands.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: John Hurley <john.hurley@netronome.com>
---
drivers/net/ethernet/netronome/nfp/abm/main.h | 26 +++---
.../net/ethernet/netronome/nfp/abm/qdisc.c | 88 ++++++++++++-------
2 files changed, 74 insertions(+), 40 deletions(-)
diff --git a/drivers/net/ethernet/netronome/nfp/abm/main.h b/drivers/net/ethernet/netronome/nfp/abm/main.h
index 054228c29184..47888288a706 100644
--- a/drivers/net/ethernet/netronome/nfp/abm/main.h
+++ b/drivers/net/ethernet/netronome/nfp/abm/main.h
@@ -112,11 +112,13 @@ enum nfp_qdisc_type {
* @mq.prev_stats: previously reported @mq.stats
*
* @red: RED Qdisc specific parameters and state
- * @red.threshold: ECN marking threshold
- * @red.stats: current stats of the RED Qdisc
- * @red.prev_stats: previously reported @red.stats
- * @red.xstats: extended stats for RED - current
- * @red.prev_xstats: extended stats for RED - previously reported
+ * @red.num_bands: Number of valid entries in the @red.band table
+ * @red.band: Per-band array of RED instances
+ * @red.band.threshold: ECN marking threshold
+ * @red.band.stats: current stats of the RED Qdisc
+ * @red.band.prev_stats: previously reported @red.stats
+ * @red.band.xstats: extended stats for RED - current
+ * @red.band.prev_xstats: extended stats for RED - previously reported
*/
struct nfp_qdisc {
struct net_device *netdev;
@@ -139,11 +141,15 @@ struct nfp_qdisc {
} mq;
/* TC_SETUP_QDISC_RED */
struct {
- u32 threshold;
- struct nfp_alink_stats stats;
- struct nfp_alink_stats prev_stats;
- struct nfp_alink_xstats xstats;
- struct nfp_alink_xstats prev_xstats;
+ unsigned int num_bands;
+
+ struct {
+ u32 threshold;
+ struct nfp_alink_stats stats;
+ struct nfp_alink_stats prev_stats;
+ struct nfp_alink_xstats xstats;
+ struct nfp_alink_xstats prev_xstats;
+ } band[1];
} red;
};
};
diff --git a/drivers/net/ethernet/netronome/nfp/abm/qdisc.c b/drivers/net/ethernet/netronome/nfp/abm/qdisc.c
index 251ce3070564..b65b3177c94a 100644
--- a/drivers/net/ethernet/netronome/nfp/abm/qdisc.c
+++ b/drivers/net/ethernet/netronome/nfp/abm/qdisc.c
@@ -46,20 +46,25 @@ nfp_abm_stats_update_red(struct nfp_abm_link *alink, struct nfp_qdisc *qdisc,
unsigned int queue)
{
struct nfp_cpp *cpp = alink->abm->app->cpp;
+ unsigned int i;
int err;
if (!qdisc->offloaded)
return;
- err = nfp_abm_ctrl_read_q_stats(alink, 0, queue, &qdisc->red.stats);
- if (err)
- nfp_err(cpp, "RED stats (%d, %d) read failed with error %d\n",
- 0, queue, err);
-
- err = nfp_abm_ctrl_read_q_xstats(alink, 0, queue, &qdisc->red.xstats);
- if (err)
- nfp_err(cpp, "RED xstats (%d, %d) read failed with error %d\n",
- 0, queue, err);
+ for (i = 0; i < qdisc->red.num_bands; i++) {
+ err = nfp_abm_ctrl_read_q_stats(alink, i, queue,
+ &qdisc->red.band[i].stats);
+ if (err)
+ nfp_err(cpp, "RED stats (%d, %d) read failed with error %d\n",
+ i, queue, err);
+
+ err = nfp_abm_ctrl_read_q_xstats(alink, i, queue,
+ &qdisc->red.band[i].xstats);
+ if (err)
+ nfp_err(cpp, "RED xstats (%d, %d) read failed with error %d\n",
+ i, queue, err);
+ }
}
static void
@@ -113,6 +118,8 @@ nfp_abm_qdisc_unlink_children(struct nfp_qdisc *qdisc,
static void
nfp_abm_qdisc_offload_stop(struct nfp_abm_link *alink, struct nfp_qdisc *qdisc)
{
+ unsigned int i;
+
/* Don't complain when qdisc is getting unlinked */
if (qdisc->use_cnt)
nfp_warn(alink->abm->app->cpp, "Offload of '%08x' stopped\n",
@@ -121,8 +128,10 @@ nfp_abm_qdisc_offload_stop(struct nfp_abm_link *alink, struct nfp_qdisc *qdisc)
if (!nfp_abm_qdisc_is_red(qdisc))
return;
- qdisc->red.stats.backlog_pkts = 0;
- qdisc->red.stats.backlog_bytes = 0;
+ for (i = 0; i < qdisc->red.num_bands; i++) {
+ qdisc->red.band[i].stats.backlog_pkts = 0;
+ qdisc->red.band[i].stats.backlog_bytes = 0;
+ }
}
static int
@@ -164,15 +173,26 @@ static int
nfp_abm_stats_init(struct nfp_abm_link *alink, struct nfp_qdisc *qdisc,
unsigned int queue)
{
- return __nfp_abm_stats_init(alink, 0, queue,
- &qdisc->red.prev_stats,
- &qdisc->red.prev_xstats);
+ unsigned int i;
+ int err;
+
+ for (i = 0; i < qdisc->red.num_bands; i++) {
+ err = __nfp_abm_stats_init(alink, i, queue,
+ &qdisc->red.band[i].prev_stats,
+ &qdisc->red.band[i].prev_xstats);
+ if (err)
+ return err;
+ }
+
+ return 0;
}
static void
nfp_abm_offload_compile_red(struct nfp_abm_link *alink, struct nfp_qdisc *qdisc,
unsigned int queue)
{
+ unsigned int i;
+
qdisc->offload_mark = qdisc->type == NFP_QDISC_RED &&
qdisc->params_ok &&
qdisc->use_cnt == 1 &&
@@ -186,7 +206,9 @@ nfp_abm_offload_compile_red(struct nfp_abm_link *alink, struct nfp_qdisc *qdisc,
if (!qdisc->offload_mark)
return;
- nfp_abm_ctrl_set_q_lvl(alink, 0, queue, qdisc->red.threshold);
+ for (i = 0; i < alink->abm->num_bands; i++)
+ nfp_abm_ctrl_set_q_lvl(alink, i, queue,
+ qdisc->red.band[i].threshold);
}
static void
@@ -217,8 +239,10 @@ void nfp_abm_qdisc_offload_update(struct nfp_abm_link *alink)
size_t i;
/* Mark all thresholds as unconfigured */
- __bitmap_set(abm->threshold_undef,
- alink->queue_base, alink->total_queues);
+ for (i = 0; i < abm->num_bands; i++)
+ __bitmap_set(abm->threshold_undef,
+ i * NFP_NET_MAX_RX_RINGS + alink->queue_base,
+ alink->total_queues);
/* Clear offload marks */
radix_tree_for_each_slot(slot, &alink->qdiscs, &iter, 0) {
@@ -451,10 +475,10 @@ nfp_abm_red_xstats(struct nfp_abm_link *alink, struct tc_red_qopt_offload *opt)
if (!qdisc || !qdisc->offloaded)
return -EOPNOTSUPP;
- nfp_abm_stats_red_calculate(&qdisc->red.xstats,
- &qdisc->red.prev_xstats,
+ nfp_abm_stats_red_calculate(&qdisc->red.band[0].xstats,
+ &qdisc->red.band[0].prev_xstats,
opt->xstats);
- qdisc->red.prev_xstats = qdisc->red.xstats;
+ qdisc->red.band[0].prev_xstats = qdisc->red.band[0].xstats;
return 0;
}
@@ -473,10 +497,10 @@ nfp_abm_red_stats(struct nfp_abm_link *alink, u32 handle,
* counters back so carry on even if qdisc is not currently offloaded.
*/
- nfp_abm_stats_calculate(&qdisc->red.stats,
- &qdisc->red.prev_stats,
+ nfp_abm_stats_calculate(&qdisc->red.band[0].stats,
+ &qdisc->red.band[0].prev_stats,
stats->bstats, stats->qstats);
- qdisc->red.prev_stats = qdisc->red.stats;
+ qdisc->red.band[0].prev_stats = qdisc->red.band[0].stats;
return qdisc->offloaded ? 0 : -EOPNOTSUPP;
}
@@ -538,8 +562,10 @@ nfp_abm_red_replace(struct net_device *netdev, struct nfp_abm_link *alink,
}
qdisc->params_ok = nfp_abm_red_check_params(alink, opt);
- if (qdisc->params_ok)
- qdisc->red.threshold = opt->set.min;
+ if (qdisc->params_ok) {
+ qdisc->red.num_bands = 1;
+ qdisc->red.band[0].threshold = opt->set.min;
+ }
if (qdisc->use_cnt == 1)
nfp_abm_qdisc_offload_update(alink);
@@ -592,7 +618,7 @@ nfp_abm_mq_stats(struct nfp_abm_link *alink, u32 handle,
struct tc_qopt_offload_stats *stats)
{
struct nfp_qdisc *qdisc, *red;
- unsigned int i;
+ unsigned int i, j;
qdisc = nfp_abm_qdisc_find(alink, handle);
if (!qdisc)
@@ -614,10 +640,12 @@ nfp_abm_mq_stats(struct nfp_abm_link *alink, u32 handle,
continue;
red = qdisc->children[i];
- nfp_abm_stats_propagate(&qdisc->mq.stats,
- &red->red.stats);
- nfp_abm_stats_propagate(&qdisc->mq.prev_stats,
- &red->red.prev_stats);
+ for (j = 0; j < red->red.num_bands; j++) {
+ nfp_abm_stats_propagate(&qdisc->mq.stats,
+ &red->red.band[j].stats);
+ nfp_abm_stats_propagate(&qdisc->mq.prev_stats,
+ &red->red.band[j].prev_stats);
+ }
}
nfp_abm_stats_calculate(&qdisc->mq.stats, &qdisc->mq.prev_stats,
--
2.17.1
^ permalink raw reply related
* [PATCH net-next 06/14] net: sched: gred: add basic Qdisc offload
From: Jakub Kicinski @ 2018-11-19 23:21 UTC (permalink / raw)
To: davem; +Cc: oss-drivers, netdev, Jakub Kicinski
In-Reply-To: <20181119232150.13038-1-jakub.kicinski@netronome.com>
Add basic offload for the GRED Qdisc. Inform the drivers any
time Qdisc or virtual queue configuration changes.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: John Hurley <john.hurley@netronome.com>
---
include/linux/netdevice.h | 1 +
include/net/pkt_cls.h | 36 ++++++++++++++++++++++++++++++
net/sched/sch_gred.c | 47 +++++++++++++++++++++++++++++++++++++++
3 files changed, 84 insertions(+)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 086e64d88597..4b4207ebd5c0 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -846,6 +846,7 @@ enum tc_setup_type {
TC_SETUP_QDISC_MQ,
TC_SETUP_QDISC_ETF,
TC_SETUP_ROOT_QDISC,
+ TC_SETUP_QDISC_GRED,
};
/* These structures hold the attributes of bpf state that are being passed
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index c497ada7f591..c9198797aaed 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -868,6 +868,42 @@ struct tc_red_qopt_offload {
};
};
+enum tc_gred_command {
+ TC_GRED_REPLACE,
+ TC_GRED_DESTROY,
+};
+
+struct tc_gred_vq_qopt_offload_params {
+ bool present;
+ u32 limit;
+ u32 prio;
+ u32 min;
+ u32 max;
+ bool is_ecn;
+ bool is_harddrop;
+ u32 probability;
+ /* Only need backlog, see struct tc_prio_qopt_offload_params */
+ u32 *backlog;
+};
+
+struct tc_gred_qopt_offload_params {
+ bool grio_on;
+ bool wred_on;
+ unsigned int dp_cnt;
+ unsigned int dp_def;
+ struct gnet_stats_queue *qstats;
+ struct tc_gred_vq_qopt_offload_params tab[MAX_DPs];
+};
+
+struct tc_gred_qopt_offload {
+ enum tc_gred_command command;
+ u32 handle;
+ u32 parent;
+ union {
+ struct tc_gred_qopt_offload_params set;
+ };
+};
+
enum tc_prio_command {
TC_PRIO_REPLACE,
TC_PRIO_DESTROY,
diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c
index 8b8c325f48bc..908c9d1dfdf8 100644
--- a/net/sched/sch_gred.c
+++ b/net/sched/sch_gred.c
@@ -23,6 +23,7 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
+#include <net/pkt_cls.h>
#include <net/pkt_sched.h>
#include <net/red.h>
@@ -311,6 +312,48 @@ static void gred_reset(struct Qdisc *sch)
}
}
+static void gred_offload(struct Qdisc *sch, enum tc_gred_command command)
+{
+ struct gred_sched *table = qdisc_priv(sch);
+ struct net_device *dev = qdisc_dev(sch);
+ struct tc_gred_qopt_offload opt = {
+ .command = command,
+ .handle = sch->handle,
+ .parent = sch->parent,
+ };
+
+ if (!tc_can_offload(dev) || !dev->netdev_ops->ndo_setup_tc)
+ return;
+
+ if (command == TC_GRED_REPLACE) {
+ unsigned int i;
+
+ opt.set.grio_on = gred_rio_mode(table);
+ opt.set.wred_on = gred_wred_mode(table);
+ opt.set.dp_cnt = table->DPs;
+ opt.set.dp_def = table->def;
+
+ for (i = 0; i < table->DPs; i++) {
+ struct gred_sched_data *q = table->tab[i];
+
+ if (!q)
+ continue;
+ opt.set.tab[i].present = true;
+ opt.set.tab[i].limit = q->limit;
+ opt.set.tab[i].prio = q->prio;
+ opt.set.tab[i].min = q->parms.qth_min >> q->parms.Wlog;
+ opt.set.tab[i].max = q->parms.qth_max >> q->parms.Wlog;
+ opt.set.tab[i].is_ecn = gred_use_ecn(q);
+ opt.set.tab[i].is_harddrop = gred_use_harddrop(q);
+ opt.set.tab[i].probability = q->parms.max_P;
+ opt.set.tab[i].backlog = &q->backlog;
+ }
+ opt.set.qstats = &sch->qstats;
+ }
+
+ dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_GRED, &opt);
+}
+
static inline void gred_destroy_vq(struct gred_sched_data *q)
{
kfree(q);
@@ -385,6 +428,7 @@ static int gred_change_table_def(struct Qdisc *sch, struct nlattr *dps,
}
}
+ gred_offload(sch, TC_GRED_REPLACE);
return 0;
}
@@ -630,6 +674,8 @@ static int gred_change(struct Qdisc *sch, struct nlattr *opt,
sch_tree_unlock(sch);
kfree(prealloc);
+
+ gred_offload(sch, TC_GRED_REPLACE);
return 0;
err_unlock_free:
@@ -815,6 +861,7 @@ static void gred_destroy(struct Qdisc *sch)
if (table->tab[i])
gred_destroy_vq(table->tab[i]);
}
+ gred_offload(sch, TC_GRED_DESTROY);
}
static struct Qdisc_ops gred_qdisc_ops __read_mostly = {
--
2.17.1
^ permalink raw reply related
* [PATCH net-next 04/14] nfp: abm: switch to extended stats for reading packet/byte counts
From: Jakub Kicinski @ 2018-11-19 23:21 UTC (permalink / raw)
To: davem; +Cc: oss-drivers, netdev, Jakub Kicinski
In-Reply-To: <20181119232150.13038-1-jakub.kicinski@netronome.com>
In PRIO-enabled FW read the statistics from per-band symbol, rather
than from the standard per-PCIe-queue counters.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: John Hurley <john.hurley@netronome.com>
---
drivers/net/ethernet/netronome/nfp/abm/ctrl.c | 47 +++++++++++++++++--
drivers/net/ethernet/netronome/nfp/abm/main.h | 2 +
2 files changed, 46 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/netronome/nfp/abm/ctrl.c b/drivers/net/ethernet/netronome/nfp/abm/ctrl.c
index 8b2598a223de..013ba6c85d2b 100644
--- a/drivers/net/ethernet/netronome/nfp/abm/ctrl.c
+++ b/drivers/net/ethernet/netronome/nfp/abm/ctrl.c
@@ -28,6 +28,11 @@
#define NFP_QMSTAT_DROP 16
#define NFP_QMSTAT_ECN 24
+#define NFP_Q_STAT_SYM_NAME "_abi_nfd_rxq_stats%u%s"
+#define NFP_Q_STAT_STRIDE 16
+#define NFP_Q_STAT_PKTS 0
+#define NFP_Q_STAT_BYTES 8
+
static int
nfp_abm_ctrl_stat(struct nfp_abm_link *alink, const struct nfp_rtsym *sym,
unsigned int stride, unsigned int offset, unsigned int band,
@@ -109,14 +114,42 @@ u64 nfp_abm_ctrl_stat_sto(struct nfp_abm_link *alink, unsigned int i)
return val;
}
+static int
+nfp_abm_ctrl_stat_basic(struct nfp_abm_link *alink, unsigned int band,
+ unsigned int queue, unsigned int off, u64 *val)
+{
+ if (!nfp_abm_has_prio(alink->abm)) {
+ if (!band) {
+ unsigned int id = alink->queue_base + queue;
+
+ *val = nn_readq(alink->vnic,
+ NFP_NET_CFG_RXR_STATS(id) + off);
+ } else {
+ *val = 0;
+ }
+
+ return 0;
+ } else {
+ return nfp_abm_ctrl_stat(alink, alink->abm->q_stats,
+ NFP_Q_STAT_STRIDE, off, band, queue,
+ true, val);
+ }
+}
+
int nfp_abm_ctrl_read_q_stats(struct nfp_abm_link *alink, unsigned int band,
unsigned int queue, struct nfp_alink_stats *stats)
{
int err;
- stats->tx_pkts += nn_readq(alink->vnic, NFP_NET_CFG_RXR_STATS(queue));
- stats->tx_bytes += nn_readq(alink->vnic,
- NFP_NET_CFG_RXR_STATS(queue) + 8);
+ err = nfp_abm_ctrl_stat_basic(alink, band, queue, NFP_Q_STAT_PKTS,
+ &stats->tx_pkts);
+ if (err)
+ return err;
+
+ err = nfp_abm_ctrl_stat_basic(alink, band, queue, NFP_Q_STAT_BYTES,
+ &stats->tx_bytes);
+ if (err)
+ return err;
err = nfp_abm_ctrl_stat(alink, alink->abm->q_lvls, NFP_QLVL_STRIDE,
NFP_QLVL_BLOG_BYTES, band, queue, false,
@@ -251,5 +284,13 @@ int nfp_abm_ctrl_find_addrs(struct nfp_abm *abm)
return PTR_ERR(sym);
abm->qm_stats = sym;
+ if (nfp_abm_has_prio(abm)) {
+ sym = nfp_abm_ctrl_find_q_rtsym(abm, NFP_Q_STAT_SYM_NAME,
+ NFP_Q_STAT_STRIDE);
+ if (IS_ERR(sym))
+ return PTR_ERR(sym);
+ abm->q_stats = sym;
+ }
+
return 0;
}
diff --git a/drivers/net/ethernet/netronome/nfp/abm/main.h b/drivers/net/ethernet/netronome/nfp/abm/main.h
index b18a699dac50..054228c29184 100644
--- a/drivers/net/ethernet/netronome/nfp/abm/main.h
+++ b/drivers/net/ethernet/netronome/nfp/abm/main.h
@@ -38,6 +38,7 @@ struct nfp_net;
* in switchdev mode
* @q_lvls: queue level control area
* @qm_stats: queue statistics symbol
+ * @q_stats: basic queue statistics (only in per-band case)
*/
struct nfp_abm {
struct nfp_app *app;
@@ -53,6 +54,7 @@ struct nfp_abm {
enum devlink_eswitch_mode eswitch_mode;
const struct nfp_rtsym *q_lvls;
const struct nfp_rtsym *qm_stats;
+ const struct nfp_rtsym *q_stats;
};
/**
--
2.17.1
^ permalink raw reply related
* [PATCH net-next 05/14] nfp: abm: add up bands for sto/non-sto stats
From: Jakub Kicinski @ 2018-11-19 23:21 UTC (permalink / raw)
To: davem; +Cc: oss-drivers, netdev, Jakub Kicinski
In-Reply-To: <20181119232150.13038-1-jakub.kicinski@netronome.com>
Add up stats for all bands for the extra ethtool statistics.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: John Hurley <john.hurley@netronome.com>
---
drivers/net/ethernet/netronome/nfp/abm/ctrl.c | 36 ++++++++++++-------
1 file changed, 24 insertions(+), 12 deletions(-)
diff --git a/drivers/net/ethernet/netronome/nfp/abm/ctrl.c b/drivers/net/ethernet/netronome/nfp/abm/ctrl.c
index 013ba6c85d2b..10a571b5b565 100644
--- a/drivers/net/ethernet/netronome/nfp/abm/ctrl.c
+++ b/drivers/net/ethernet/netronome/nfp/abm/ctrl.c
@@ -94,24 +94,36 @@ int nfp_abm_ctrl_set_q_lvl(struct nfp_abm_link *alink, unsigned int band,
return __nfp_abm_ctrl_set_q_lvl(alink->abm, threshold, val);
}
-u64 nfp_abm_ctrl_stat_non_sto(struct nfp_abm_link *alink, unsigned int i)
+u64 nfp_abm_ctrl_stat_non_sto(struct nfp_abm_link *alink, unsigned int queue)
{
- u64 val;
+ unsigned int band;
+ u64 val, sum = 0;
+
+ for (band = 0; band < alink->abm->num_bands; band++) {
+ if (nfp_abm_ctrl_stat(alink, alink->abm->qm_stats,
+ NFP_QMSTAT_STRIDE, NFP_QMSTAT_NON_STO,
+ band, queue, true, &val))
+ return 0;
+ sum += val;
+ }
- if (nfp_abm_ctrl_stat(alink, alink->abm->qm_stats, NFP_QMSTAT_STRIDE,
- NFP_QMSTAT_NON_STO, 0, i, true, &val))
- return 0;
- return val;
+ return sum;
}
-u64 nfp_abm_ctrl_stat_sto(struct nfp_abm_link *alink, unsigned int i)
+u64 nfp_abm_ctrl_stat_sto(struct nfp_abm_link *alink, unsigned int queue)
{
- u64 val;
+ unsigned int band;
+ u64 val, sum = 0;
+
+ for (band = 0; band < alink->abm->num_bands; band++) {
+ if (nfp_abm_ctrl_stat(alink, alink->abm->qm_stats,
+ NFP_QMSTAT_STRIDE, NFP_QMSTAT_STO,
+ band, queue, true, &val))
+ return 0;
+ sum += val;
+ }
- if (nfp_abm_ctrl_stat(alink, alink->abm->qm_stats, NFP_QMSTAT_STRIDE,
- NFP_QMSTAT_STO, 0, i, true, &val))
- return 0;
- return val;
+ return sum;
}
static int
--
2.17.1
^ permalink raw reply related
* [PATCH net-next 03/14] nfp: abm: size threshold table to account for bands
From: Jakub Kicinski @ 2018-11-19 23:21 UTC (permalink / raw)
To: davem; +Cc: oss-drivers, netdev, Jakub Kicinski
In-Reply-To: <20181119232150.13038-1-jakub.kicinski@netronome.com>
Make sure the threshold table is large enough to hold information
for all bands.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: John Hurley <john.hurley@netronome.com>
---
drivers/net/ethernet/netronome/nfp/abm/main.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/netronome/nfp/abm/main.c b/drivers/net/ethernet/netronome/nfp/abm/main.c
index a5732d3bd1b7..b21250b95475 100644
--- a/drivers/net/ethernet/netronome/nfp/abm/main.c
+++ b/drivers/net/ethernet/netronome/nfp/abm/main.c
@@ -422,7 +422,7 @@ static int nfp_abm_init(struct nfp_app *app)
goto err_free_abm;
err = -ENOMEM;
- abm->num_thresholds = NFP_NET_MAX_RX_RINGS;
+ abm->num_thresholds = array_size(abm->num_bands, NFP_NET_MAX_RX_RINGS);
abm->threshold_undef = bitmap_zalloc(abm->num_thresholds, GFP_KERNEL);
if (!abm->threshold_undef)
goto err_free_abm;
@@ -431,7 +431,7 @@ static int nfp_abm_init(struct nfp_app *app)
sizeof(*abm->thresholds), GFP_KERNEL);
if (!abm->thresholds)
goto err_free_thresh_umap;
- for (i = 0; i < NFP_NET_MAX_RX_RINGS; i++)
+ for (i = 0; i < abm->num_bands * NFP_NET_MAX_RX_RINGS; i++)
__nfp_abm_ctrl_set_q_lvl(abm, i, NFP_ABM_LVL_INFINITY);
/* We start in legacy mode, make sure advanced queuing is disabled */
--
2.17.1
^ permalink raw reply related
* [PATCH net-next 02/14] nfp: abm: pass band parameter to functions
From: Jakub Kicinski @ 2018-11-19 23:21 UTC (permalink / raw)
To: davem; +Cc: oss-drivers, netdev, Jakub Kicinski
In-Reply-To: <20181119232150.13038-1-jakub.kicinski@netronome.com>
In preparation for per-band RED offload pass band parameter to
functions. For now it will always be 0.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: John Hurley <john.hurley@netronome.com>
---
drivers/net/ethernet/netronome/nfp/abm/ctrl.c | 52 ++++++++++---------
drivers/net/ethernet/netronome/nfp/abm/main.h | 10 ++--
.../net/ethernet/netronome/nfp/abm/qdisc.c | 30 +++++------
3 files changed, 49 insertions(+), 43 deletions(-)
diff --git a/drivers/net/ethernet/netronome/nfp/abm/ctrl.c b/drivers/net/ethernet/netronome/nfp/abm/ctrl.c
index d9c5fff97547..8b2598a223de 100644
--- a/drivers/net/ethernet/netronome/nfp/abm/ctrl.c
+++ b/drivers/net/ethernet/netronome/nfp/abm/ctrl.c
@@ -30,23 +30,25 @@
static int
nfp_abm_ctrl_stat(struct nfp_abm_link *alink, const struct nfp_rtsym *sym,
- unsigned int stride, unsigned int offset, unsigned int i,
- bool is_u64, u64 *res)
+ unsigned int stride, unsigned int offset, unsigned int band,
+ unsigned int queue, bool is_u64, u64 *res)
{
struct nfp_cpp *cpp = alink->abm->app->cpp;
u64 val, sym_offset;
+ unsigned int qid;
u32 val32;
int err;
- sym_offset = (alink->queue_base + i) * stride + offset;
+ qid = band * NFP_NET_MAX_RX_RINGS + alink->queue_base + queue;
+
+ sym_offset = qid * stride + offset;
if (is_u64)
err = __nfp_rtsym_readq(cpp, sym, 3, 0, sym_offset, &val);
else
err = __nfp_rtsym_readl(cpp, sym, 3, 0, sym_offset, &val32);
if (err) {
- nfp_err(cpp,
- "RED offload reading stat failed on vNIC %d queue %d\n",
- alink->id, i);
+ nfp_err(cpp, "RED offload reading stat failed on vNIC %d band %d queue %d (+ %d)\n",
+ alink->id, band, queue, alink->queue_base);
return err;
}
@@ -77,12 +79,12 @@ int __nfp_abm_ctrl_set_q_lvl(struct nfp_abm *abm, unsigned int id, u32 val)
return 0;
}
-int nfp_abm_ctrl_set_q_lvl(struct nfp_abm_link *alink, unsigned int queue,
- u32 val)
+int nfp_abm_ctrl_set_q_lvl(struct nfp_abm_link *alink, unsigned int band,
+ unsigned int queue, u32 val)
{
unsigned int threshold;
- threshold = alink->queue_base + queue;
+ threshold = band * NFP_NET_MAX_RX_RINGS + alink->queue_base + queue;
return __nfp_abm_ctrl_set_q_lvl(alink->abm, threshold, val);
}
@@ -92,7 +94,7 @@ u64 nfp_abm_ctrl_stat_non_sto(struct nfp_abm_link *alink, unsigned int i)
u64 val;
if (nfp_abm_ctrl_stat(alink, alink->abm->qm_stats, NFP_QMSTAT_STRIDE,
- NFP_QMSTAT_NON_STO, i, true, &val))
+ NFP_QMSTAT_NON_STO, 0, i, true, &val))
return 0;
return val;
}
@@ -102,56 +104,58 @@ u64 nfp_abm_ctrl_stat_sto(struct nfp_abm_link *alink, unsigned int i)
u64 val;
if (nfp_abm_ctrl_stat(alink, alink->abm->qm_stats, NFP_QMSTAT_STRIDE,
- NFP_QMSTAT_STO, i, true, &val))
+ NFP_QMSTAT_STO, 0, i, true, &val))
return 0;
return val;
}
-int nfp_abm_ctrl_read_q_stats(struct nfp_abm_link *alink, unsigned int i,
- struct nfp_alink_stats *stats)
+int nfp_abm_ctrl_read_q_stats(struct nfp_abm_link *alink, unsigned int band,
+ unsigned int queue, struct nfp_alink_stats *stats)
{
int err;
- stats->tx_pkts = nn_readq(alink->vnic, NFP_NET_CFG_RXR_STATS(i));
- stats->tx_bytes = nn_readq(alink->vnic, NFP_NET_CFG_RXR_STATS(i) + 8);
+ stats->tx_pkts += nn_readq(alink->vnic, NFP_NET_CFG_RXR_STATS(queue));
+ stats->tx_bytes += nn_readq(alink->vnic,
+ NFP_NET_CFG_RXR_STATS(queue) + 8);
- err = nfp_abm_ctrl_stat(alink, alink->abm->q_lvls,
- NFP_QLVL_STRIDE, NFP_QLVL_BLOG_BYTES,
- i, false, &stats->backlog_bytes);
+ err = nfp_abm_ctrl_stat(alink, alink->abm->q_lvls, NFP_QLVL_STRIDE,
+ NFP_QLVL_BLOG_BYTES, band, queue, false,
+ &stats->backlog_bytes);
if (err)
return err;
err = nfp_abm_ctrl_stat(alink, alink->abm->q_lvls,
NFP_QLVL_STRIDE, NFP_QLVL_BLOG_PKTS,
- i, false, &stats->backlog_pkts);
+ band, queue, false, &stats->backlog_pkts);
if (err)
return err;
err = nfp_abm_ctrl_stat(alink, alink->abm->qm_stats,
NFP_QMSTAT_STRIDE, NFP_QMSTAT_DROP,
- i, true, &stats->drops);
+ band, queue, true, &stats->drops);
if (err)
return err;
return nfp_abm_ctrl_stat(alink, alink->abm->qm_stats,
NFP_QMSTAT_STRIDE, NFP_QMSTAT_ECN,
- i, true, &stats->overlimits);
+ band, queue, true, &stats->overlimits);
}
-int nfp_abm_ctrl_read_q_xstats(struct nfp_abm_link *alink, unsigned int i,
+int nfp_abm_ctrl_read_q_xstats(struct nfp_abm_link *alink,
+ unsigned int band, unsigned int queue,
struct nfp_alink_xstats *xstats)
{
int err;
err = nfp_abm_ctrl_stat(alink, alink->abm->qm_stats,
NFP_QMSTAT_STRIDE, NFP_QMSTAT_DROP,
- i, true, &xstats->pdrop);
+ band, queue, true, &xstats->pdrop);
if (err)
return err;
return nfp_abm_ctrl_stat(alink, alink->abm->qm_stats,
NFP_QMSTAT_STRIDE, NFP_QMSTAT_ECN,
- i, true, &xstats->ecn_marked);
+ band, queue, true, &xstats->ecn_marked);
}
int nfp_abm_ctrl_qm_enable(struct nfp_abm *abm)
diff --git a/drivers/net/ethernet/netronome/nfp/abm/main.h b/drivers/net/ethernet/netronome/nfp/abm/main.h
index b10c067b15c8..b18a699dac50 100644
--- a/drivers/net/ethernet/netronome/nfp/abm/main.h
+++ b/drivers/net/ethernet/netronome/nfp/abm/main.h
@@ -188,11 +188,13 @@ int nfp_abm_setup_tc_mq(struct net_device *netdev, struct nfp_abm_link *alink,
void nfp_abm_ctrl_read_params(struct nfp_abm_link *alink);
int nfp_abm_ctrl_find_addrs(struct nfp_abm *abm);
int __nfp_abm_ctrl_set_q_lvl(struct nfp_abm *abm, unsigned int id, u32 val);
-int nfp_abm_ctrl_set_q_lvl(struct nfp_abm_link *alink, unsigned int queue,
- u32 val);
-int nfp_abm_ctrl_read_q_stats(struct nfp_abm_link *alink, unsigned int i,
+int nfp_abm_ctrl_set_q_lvl(struct nfp_abm_link *alink, unsigned int band,
+ unsigned int queue, u32 val);
+int nfp_abm_ctrl_read_q_stats(struct nfp_abm_link *alink,
+ unsigned int band, unsigned int queue,
struct nfp_alink_stats *stats);
-int nfp_abm_ctrl_read_q_xstats(struct nfp_abm_link *alink, unsigned int i,
+int nfp_abm_ctrl_read_q_xstats(struct nfp_abm_link *alink,
+ unsigned int band, unsigned int queue,
struct nfp_alink_xstats *xstats);
u64 nfp_abm_ctrl_stat_non_sto(struct nfp_abm_link *alink, unsigned int i);
u64 nfp_abm_ctrl_stat_sto(struct nfp_abm_link *alink, unsigned int i);
diff --git a/drivers/net/ethernet/netronome/nfp/abm/qdisc.c b/drivers/net/ethernet/netronome/nfp/abm/qdisc.c
index 16c4afe3a37f..251ce3070564 100644
--- a/drivers/net/ethernet/netronome/nfp/abm/qdisc.c
+++ b/drivers/net/ethernet/netronome/nfp/abm/qdisc.c
@@ -51,15 +51,15 @@ nfp_abm_stats_update_red(struct nfp_abm_link *alink, struct nfp_qdisc *qdisc,
if (!qdisc->offloaded)
return;
- err = nfp_abm_ctrl_read_q_stats(alink, queue, &qdisc->red.stats);
+ err = nfp_abm_ctrl_read_q_stats(alink, 0, queue, &qdisc->red.stats);
if (err)
- nfp_err(cpp, "RED stats (%d) read failed with error %d\n",
- queue, err);
+ nfp_err(cpp, "RED stats (%d, %d) read failed with error %d\n",
+ 0, queue, err);
- err = nfp_abm_ctrl_read_q_xstats(alink, queue, &qdisc->red.xstats);
+ err = nfp_abm_ctrl_read_q_xstats(alink, 0, queue, &qdisc->red.xstats);
if (err)
- nfp_err(cpp, "RED xstats (%d) read failed with error %d\n",
- queue, err);
+ nfp_err(cpp, "RED xstats (%d, %d) read failed with error %d\n",
+ 0, queue, err);
}
static void
@@ -126,7 +126,7 @@ nfp_abm_qdisc_offload_stop(struct nfp_abm_link *alink, struct nfp_qdisc *qdisc)
}
static int
-__nfp_abm_stats_init(struct nfp_abm_link *alink,
+__nfp_abm_stats_init(struct nfp_abm_link *alink, unsigned int band,
unsigned int queue, struct nfp_alink_stats *prev_stats,
struct nfp_alink_xstats *prev_xstats)
{
@@ -139,19 +139,19 @@ __nfp_abm_stats_init(struct nfp_abm_link *alink,
backlog_pkts = prev_stats->backlog_pkts;
backlog_bytes = prev_stats->backlog_bytes;
- err = nfp_abm_ctrl_read_q_stats(alink, queue, prev_stats);
+ err = nfp_abm_ctrl_read_q_stats(alink, band, queue, prev_stats);
if (err) {
nfp_err(alink->abm->app->cpp,
- "RED stats init (%d) failed with error %d\n",
- queue, err);
+ "RED stats init (%d, %d) failed with error %d\n",
+ band, queue, err);
return err;
}
- err = nfp_abm_ctrl_read_q_xstats(alink, queue, prev_xstats);
+ err = nfp_abm_ctrl_read_q_xstats(alink, band, queue, prev_xstats);
if (err) {
nfp_err(alink->abm->app->cpp,
- "RED xstats init (%d) failed with error %d\n",
- queue, err);
+ "RED xstats init (%d, %d) failed with error %d\n",
+ band, queue, err);
return err;
}
@@ -164,7 +164,7 @@ static int
nfp_abm_stats_init(struct nfp_abm_link *alink, struct nfp_qdisc *qdisc,
unsigned int queue)
{
- return __nfp_abm_stats_init(alink, queue,
+ return __nfp_abm_stats_init(alink, 0, queue,
&qdisc->red.prev_stats,
&qdisc->red.prev_xstats);
}
@@ -186,7 +186,7 @@ nfp_abm_offload_compile_red(struct nfp_abm_link *alink, struct nfp_qdisc *qdisc,
if (!qdisc->offload_mark)
return;
- nfp_abm_ctrl_set_q_lvl(alink, queue, qdisc->red.threshold);
+ nfp_abm_ctrl_set_q_lvl(alink, 0, queue, qdisc->red.threshold);
}
static void
--
2.17.1
^ permalink raw reply related
* [PATCH net-next 01/14] nfp: abm: map per-band symbols
From: Jakub Kicinski @ 2018-11-19 23:21 UTC (permalink / raw)
To: davem; +Cc: oss-drivers, netdev, Jakub Kicinski
In-Reply-To: <20181119232150.13038-1-jakub.kicinski@netronome.com>
In preparation for multi-band RED offload if FW is capable map
the extended symbols which will allow us to set per-band parameters
and read stats.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: John Hurley <john.hurley@netronome.com>
---
drivers/net/ethernet/netronome/nfp/abm/ctrl.c | 56 ++++++++++++++-----
drivers/net/ethernet/netronome/nfp/abm/main.h | 11 ++++
2 files changed, 54 insertions(+), 13 deletions(-)
diff --git a/drivers/net/ethernet/netronome/nfp/abm/ctrl.c b/drivers/net/ethernet/netronome/nfp/abm/ctrl.c
index 1629b07f727b..d9c5fff97547 100644
--- a/drivers/net/ethernet/netronome/nfp/abm/ctrl.c
+++ b/drivers/net/ethernet/netronome/nfp/abm/ctrl.c
@@ -2,6 +2,7 @@
/* Copyright (C) 2018 Netronome Systems, Inc. */
#include <linux/kernel.h>
+#include <linux/log2.h>
#include "../nfpcore/nfp_cpp.h"
#include "../nfpcore/nfp_nffw.h"
@@ -11,13 +12,16 @@
#include "../nfp_net.h"
#include "main.h"
-#define NFP_QLVL_SYM_NAME "_abi_nfd_out_q_lvls_%u"
+#define NFP_NUM_PRIOS_SYM_NAME "_abi_pci_dscp_num_prio_%u"
+#define NFP_NUM_BANDS_SYM_NAME "_abi_pci_dscp_num_band_%u"
+
+#define NFP_QLVL_SYM_NAME "_abi_nfd_out_q_lvls_%u%s"
#define NFP_QLVL_STRIDE 16
#define NFP_QLVL_BLOG_BYTES 0
#define NFP_QLVL_BLOG_PKTS 4
#define NFP_QLVL_THRS 8
-#define NFP_QMSTAT_SYM_NAME "_abi_nfdqm%u_stats"
+#define NFP_QMSTAT_SYM_NAME "_abi_nfdqm%u_stats%s"
#define NFP_QMSTAT_STRIDE 32
#define NFP_QMSTAT_NON_STO 0
#define NFP_QMSTAT_STO 8
@@ -189,30 +193,56 @@ nfp_abm_ctrl_find_rtsym(struct nfp_pf *pf, const char *name, unsigned int size)
}
static const struct nfp_rtsym *
-nfp_abm_ctrl_find_q_rtsym(struct nfp_pf *pf, const char *name,
- unsigned int size)
+nfp_abm_ctrl_find_q_rtsym(struct nfp_abm *abm, const char *name_fmt,
+ size_t size)
{
- return nfp_abm_ctrl_find_rtsym(pf, name, size * NFP_NET_MAX_RX_RINGS);
+ char pf_symbol[64];
+
+ size = array3_size(size, abm->num_bands, NFP_NET_MAX_RX_RINGS);
+ snprintf(pf_symbol, sizeof(pf_symbol), name_fmt,
+ abm->pf_id, nfp_abm_has_prio(abm) ? "_per_band" : "");
+
+ return nfp_abm_ctrl_find_rtsym(abm->app->pf, pf_symbol, size);
}
int nfp_abm_ctrl_find_addrs(struct nfp_abm *abm)
{
struct nfp_pf *pf = abm->app->pf;
const struct nfp_rtsym *sym;
- unsigned int pf_id;
- char pf_symbol[64];
+ int res;
- pf_id = nfp_cppcore_pcie_unit(pf->cpp);
- abm->pf_id = pf_id;
+ abm->pf_id = nfp_cppcore_pcie_unit(pf->cpp);
+
+ /* Read count of prios and prio bands */
+ res = nfp_pf_rtsym_read_optional(pf, NFP_NUM_BANDS_SYM_NAME, 1);
+ if (res < 0)
+ return res;
+ abm->num_bands = res;
+
+ res = nfp_pf_rtsym_read_optional(pf, NFP_NUM_PRIOS_SYM_NAME, 1);
+ if (res < 0)
+ return res;
+ abm->num_prios = res;
+
+ /* Check values are sane, U16_MAX is arbitrarily chosen as max */
+ if (!is_power_of_2(abm->num_bands) || !is_power_of_2(abm->num_prios) ||
+ abm->num_bands > U16_MAX || abm->num_prios > U16_MAX ||
+ (abm->num_bands == 1) != (abm->num_prios == 1)) {
+ nfp_err(pf->cpp,
+ "invalid priomap description num bands: %u and num prios: %u\n",
+ abm->num_bands, abm->num_prios);
+ return -EINVAL;
+ }
- snprintf(pf_symbol, sizeof(pf_symbol), NFP_QLVL_SYM_NAME, pf_id);
- sym = nfp_abm_ctrl_find_q_rtsym(pf, pf_symbol, NFP_QLVL_STRIDE);
+ /* Find level and stat symbols */
+ sym = nfp_abm_ctrl_find_q_rtsym(abm, NFP_QLVL_SYM_NAME,
+ NFP_QLVL_STRIDE);
if (IS_ERR(sym))
return PTR_ERR(sym);
abm->q_lvls = sym;
- snprintf(pf_symbol, sizeof(pf_symbol), NFP_QMSTAT_SYM_NAME, pf_id);
- sym = nfp_abm_ctrl_find_q_rtsym(pf, pf_symbol, NFP_QMSTAT_STRIDE);
+ sym = nfp_abm_ctrl_find_q_rtsym(abm, NFP_QMSTAT_SYM_NAME,
+ NFP_QMSTAT_STRIDE);
if (IS_ERR(sym))
return PTR_ERR(sym);
abm->qm_stats = sym;
diff --git a/drivers/net/ethernet/netronome/nfp/abm/main.h b/drivers/net/ethernet/netronome/nfp/abm/main.h
index 240e2c8683fe..b10c067b15c8 100644
--- a/drivers/net/ethernet/netronome/nfp/abm/main.h
+++ b/drivers/net/ethernet/netronome/nfp/abm/main.h
@@ -27,6 +27,9 @@ struct nfp_net;
* @app: back pointer to nfp_app
* @pf_id: ID of our PF link
*
+ * @num_prios: number of supported DSCP priorities
+ * @num_bands: number of supported DSCP priority bands
+ *
* @thresholds: current threshold configuration
* @threshold_undef: bitmap of thresholds which have not been set
* @num_thresholds: number of @thresholds and bits in @threshold_undef
@@ -40,6 +43,9 @@ struct nfp_abm {
struct nfp_app *app;
unsigned int pf_id;
+ unsigned int num_prios;
+ unsigned int num_bands;
+
u32 *thresholds;
unsigned long *threshold_undef;
size_t num_thresholds;
@@ -166,6 +172,11 @@ struct nfp_abm_link {
struct radix_tree_root qdiscs;
};
+static inline bool nfp_abm_has_prio(struct nfp_abm *abm)
+{
+ return abm->num_bands > 1;
+}
+
void nfp_abm_qdisc_offload_update(struct nfp_abm_link *alink);
int nfp_abm_setup_root(struct net_device *netdev, struct nfp_abm_link *alink,
struct tc_root_qopt_offload *opt);
--
2.17.1
^ permalink raw reply related
* [PATCH net-next 00/14] gred: add offload support
From: Jakub Kicinski @ 2018-11-19 23:21 UTC (permalink / raw)
To: davem; +Cc: oss-drivers, netdev, Jakub Kicinski
Hi!
This series adds support for GRED offload in the nfp driver. So
far we have only supported the RED Qdisc offload, but we need a
way to differentiate traffic types e.g. based on DSCP marking.
It may seem like PRIO+RED is a good match for this job, however,
(a) we don't need strict priority behaviour of PRIO, and (b) PRIO
uses the legacy way of mapping ToS fields to bands, which is quite
awkward and limitting.
The less commonly used GRED Qdisc is a better much for the scenario,
it allows multiple sets of RED parameters and queue lengths to be
maintained with a single FIFO queue. This is exactly how nfp offload
behaves. We use a trivial u32 classifier to assign packets to virtual
queues.
There is also the minor advantage that GRED can't have its child
changed, therefore limitting ways in which the configuration of SW
path can diverge from HW offload.
Last patch of the series adds support for (G)RED in non-ECN mode,
where packets are dropped instead of marked.
Jakub Kicinski (14):
nfp: abm: map per-band symbols
nfp: abm: pass band parameter to functions
nfp: abm: size threshold table to account for bands
nfp: abm: switch to extended stats for reading packet/byte counts
nfp: abm: add up bands for sto/non-sto stats
net: sched: gred: add basic Qdisc offload
net: sched: gred: support reporting stats from offloads
nfp: abm: wrap RED parameters in bands
nfp: abm: add GRED offload
net: sched: cls_u32: add res to offload information
nfp: abm: calculate PRIO map len and check mailbox size
nfp: abm: add functions to update DSCP -> virtual queue map
nfp: abm: add cls_u32 offload for simple band classification
nfp: abm: add support for more threshold actions
drivers/net/ethernet/netronome/nfp/Makefile | 1 +
drivers/net/ethernet/netronome/nfp/abm/cls.c | 283 +++++++++++++++++
drivers/net/ethernet/netronome/nfp/abm/ctrl.c | 287 +++++++++++++++---
drivers/net/ethernet/netronome/nfp/abm/main.c | 48 ++-
drivers/net/ethernet/netronome/nfp/abm/main.h | 113 ++++++-
.../net/ethernet/netronome/nfp/abm/qdisc.c | 279 ++++++++++++++---
drivers/net/ethernet/netronome/nfp/nfp_net.h | 1 +
.../ethernet/netronome/nfp/nfp_net_common.c | 2 +-
.../net/ethernet/netronome/nfp/nfp_net_ctrl.h | 2 +
include/linux/netdevice.h | 1 +
include/net/pkt_cls.h | 45 +++
net/sched/cls_u32.c | 2 +
net/sched/sch_gred.c | 94 ++++++
13 files changed, 1042 insertions(+), 116 deletions(-)
create mode 100644 drivers/net/ethernet/netronome/nfp/abm/cls.c
--
2.17.1
^ permalink raw reply
* Re: [PATCH 10/11] nvmet-tcp: add NVMe over TCP target driver
From: David Miller @ 2018-11-19 23:18 UTC (permalink / raw)
To: sagi; +Cc: sagi, linux-block, netdev, keith.busch, hch, linux-nvme
In-Reply-To: <f4997fa5-a0f1-2783-4732-15fbd7fcafd8@grimberg.me>
From: Sagi Grimberg <sagi@grimberg.me>
Date: Mon, 19 Nov 2018 15:14:44 -0800
> Also, looking a bit closer there is a slight difference between the
> copy vs. the copy_and_csum variants. copy allows for a short_copy if
> we copy less than we expect while the csum faults it. I'm thinking
> that the copy_and_hash variant should also fault? Although I'm not
> sure I understand the fault entirely as csum is supposed to be
> cumulative, any insight?
When we are writing and signal an error, sockets have this recurring
pattern where we return immediately the amount of bytes successfully
transferred. Then on the next sendmsg() call we give the error.
I don't know if that is what is influencing the behavior here or not
but it could be.
^ permalink raw reply
* Re: [PATCH v2 RESEND update 1/2] mm/page_alloc: free order-0 pages through PCP in page_frag_free()
From: Pankaj Gupta @ 2018-11-20 9:42 UTC (permalink / raw)
To: Aaron Lu
Cc: linux-mm, linux-kernel, netdev, Andrew Morton,
Paweł Staszewski, Jesper Dangaard Brouer, Eric Dumazet,
Tariq Toukan, Ilias Apalodimas, Yoel Caspersen, Mel Gorman,
Saeed Mahameed, Michal Hocko, Vlastimil Babka, Dave Hansen,
Alexander Duyck, Ian Kumlien
In-Reply-To: <20181120014544.GB10657@intel.com>
>
> page_frag_free() calls __free_pages_ok() to free the page back to
> Buddy. This is OK for high order page, but for order-0 pages, it
> misses the optimization opportunity of using Per-Cpu-Pages and can
> cause zone lock contention when called frequently.
>
> Paweł Staszewski recently shared his result of 'how Linux kernel
> handles normal traffic'[1] and from perf data, Jesper Dangaard Brouer
> found the lock contention comes from page allocator:
>
> mlx5e_poll_tx_cq
> |
> --16.34%--napi_consume_skb
> |
> |--12.65%--__free_pages_ok
> | |
> | --11.86%--free_one_page
> | |
> | |--10.10%--queued_spin_lock_slowpath
> | |
> | --0.65%--_raw_spin_lock
> |
> |--1.55%--page_frag_free
> |
> --1.44%--skb_release_data
>
> Jesper explained how it happened: mlx5 driver RX-page recycle
> mechanism is not effective in this workload and pages have to go
> through the page allocator. The lock contention happens during
> mlx5 DMA TX completion cycle. And the page allocator cannot keep
> up at these speeds.[2]
>
> I thought that __free_pages_ok() are mostly freeing high order
> pages and thought this is an lock contention for high order pages
> but Jesper explained in detail that __free_pages_ok() here are
> actually freeing order-0 pages because mlx5 is using order-0 pages
> to satisfy its page pool allocation request.[3]
>
> The free path as pointed out by Jesper is:
> skb_free_head()
> -> skb_free_frag()
> -> page_frag_free()
> And the pages being freed on this path are order-0 pages.
>
> Fix this by doing similar things as in __page_frag_cache_drain() -
> send the being freed page to PCP if it's an order-0 page, or
> directly to Buddy if it is a high order page.
>
> With this change, Paweł hasn't noticed lock contention yet in
> his workload and Jesper has noticed a 7% performance improvement
> using a micro benchmark and lock contention is gone. Ilias' test
> on a 'low' speed 1Gbit interface on an cortex-a53 shows ~11%
> performance boost testing with 64byte packets and __free_pages_ok()
> disappeared from perf top.
>
> [1]: https://www.spinics.net/lists/netdev/msg531362.html
> [2]: https://www.spinics.net/lists/netdev/msg531421.html
> [3]: https://www.spinics.net/lists/netdev/msg531556.html
>
> Reported-by: Paweł Staszewski <pstaszewski@itcare.pl>
> Analysed-by: Jesper Dangaard Brouer <brouer@redhat.com>
> Acked-by: Vlastimil Babka <vbabka@suse.cz>
> Acked-by: Mel Gorman <mgorman@techsingularity.net>
> Acked-by: Jesper Dangaard Brouer <brouer@redhat.com>
> Acked-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
> Tested-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
> Acked-by: Alexander Duyck <alexander.h.duyck@linux.intel.com>
> Acked-by: Tariq Toukan <tariqt@mellanox.com>
> Signed-off-by: Aaron Lu <aaron.lu@intel.com>
> ---
> update: fix Tariq's email tag.
>
> mm/page_alloc.c | 10 ++++++++--
> 1 file changed, 8 insertions(+), 2 deletions(-)
>
> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> index 421c5b652708..8f8c6b33b637 100644
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
> @@ -4677,8 +4677,14 @@ void page_frag_free(void *addr)
> {
> struct page *page = virt_to_head_page(addr);
>
> - if (unlikely(put_page_testzero(page)))
> - __free_pages_ok(page, compound_order(page));
> + if (unlikely(put_page_testzero(page))) {
> + unsigned int order = compound_order(page);
> +
> + if (order == 0)
> + free_unref_page(page);
> + else
> + __free_pages_ok(page, order);
> + }
> }
> EXPORT_SYMBOL(page_frag_free);
>
> --
> 2.17.2
A good optimization for zero order allocations.
Acked-by: Pankaj gupta <pagupta@redhat.com>
Thanks,
Pankaj
^ permalink raw reply
* Re: [PATCH 10/11] nvmet-tcp: add NVMe over TCP target driver
From: Sagi Grimberg @ 2018-11-19 23:14 UTC (permalink / raw)
To: David Miller; +Cc: sagi, linux-block, netdev, keith.busch, hch, linux-nvme
In-Reply-To: <20181119.145343.2254073323355763213.davem@davemloft.net>
>> I would love you to look at skb_copy_and_hash_datagram_iter as these
>> changes will require an ack from you.
>
> My first impression is that we now have this kind of code pattern
> in at least two main places and now this will be a third.
>
> I know that nobody likes callbacks because of spectre, but all of
> these cases could be done with something like:
>
> int __skb_datagram_iter(const struct sk_buff *skb, int offset,
> struct iov_iter *to, int len,
> int (*cb)(void *, int, struct iov_iter *, void *),
> void *data)
> {
> ...
> n = cb(skb->data + offset, copy, to, data);
> ...
> }
>
> You get the idea. Then we have one version of all the loops and
> the different (copy, copy+csum, copy+hash) cases all can be
> handled by __skb_datagram_iter() but just with a different 'cb'
> and private 'data'.
I already thought about that, but the fact that we copy both a buffer
and a page to the iter (in the most general case) we'd have to carry
two callbacks for indirection.. That wasn't something I thought as
acceptable...
I guess we could rework skb_copy_datagram_iter to not call
copy_page_to_iter and open-code kmapping so we can get away with a
single code path? Unless I'm missing something?
Also, looking a bit closer there is a slight difference between the copy
vs. the copy_and_csum variants. copy allows for a short_copy if we copy
less than we expect while the csum faults it. I'm thinking that the
copy_and_hash variant should also fault? Although I'm not sure I
understand the fault entirely as csum is supposed to be cumulative, any
insight?
^ permalink raw reply
* Re: [PATCH V1 net 0/3] net: ena: hibernation and rmmod bug fixes
From: David Miller @ 2018-11-19 23:13 UTC (permalink / raw)
To: akiyano
Cc: netdev, dwmw, zorik, matua, saeedb, msw, aliguori, nafea, gtzalik,
netanel, alisaidi
In-Reply-To: <1542621922-31484-1-git-send-email-akiyano@amazon.com>
From: <akiyano@amazon.com>
Date: Mon, 19 Nov 2018 12:05:19 +0200
> From: Arthur Kiyanovski <akiyano@amazon.com>
>
> This patchset includes 2 bug fixes:
> 1. A fix to a crash during resume from hibernation.
> 2. A fix to an illegal memory access during driver removal (e.g. during rmmod)
> which might cause a crash in certain systems.
>
> The subminor number in the driver version is also promoted to indicate driver
> was changed.
Series applied, thanks.
^ permalink raw reply
* Re: [PATCH] ipv4: allow newer DSCP values in ip rules
From: David Miller @ 2018-11-19 23:11 UTC (permalink / raw)
To: mail; +Cc: netdev
In-Reply-To: <20181119090042.GA18247@rnd.infotecs.ru>
From: Pavel Balaev <mail@void.so>
Date: Mon, 19 Nov 2018 12:00:45 +0300
> After this patch this one can use it:
You can "configure it" but it doesn't work at all.
Did you test this in any way beyond simply dumping the FIB rule
tables?
The whole kernel masks the TOS value using RT_TOS() so it is going to
clear out those extra bits every time the configured value actually
gets used.
^ permalink raw reply
* [PATCH v2 4/5] Bluetooth: btusb: Collect the common Intel assignments together
From: Rajat Jain @ 2018-11-19 23:04 UTC (permalink / raw)
To: Marcel Holtmann, Johan Hedberg, Greg Kroah-Hartman,
David S. Miller, Dmitry Torokhov, Rajat Jain, Alex Hung,
linux-bluetooth, linux-kernel, linux-usb, netdev
Cc: rajatxjain, dtor, raghuram.hegde, chethan.tumkur.narayan,
sukumar.ghorai
In-Reply-To: <20181119230409.258121-1-rajatja@google.com>
The BTUSB_INTEL and BTUSB_INTEL_NEW have common functions & quirks are
assigned to hdev structure. Lets collect them together instead of
repeating them in different code branches.
Signed-off-by: Rajat Jain <rajatja@google.com>
---
v2: same as v1
drivers/bluetooth/btusb.c | 27 ++++++++++++---------------
1 file changed, 12 insertions(+), 15 deletions(-)
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 7439a7eb50ac..e8e148480c91 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -3077,28 +3077,25 @@ static int btusb_probe(struct usb_interface *intf,
data->diag = usb_ifnum_to_if(data->udev, ifnum_base + 2);
}
#endif
+ if (id->driver_info & BTUSB_INTEL ||
+ id->driver_info & BTUSB_INTEL_NEW) {
- if (id->driver_info & BTUSB_INTEL) {
hdev->manufacturer = 2;
- hdev->setup = btusb_setup_intel;
- hdev->shutdown = btusb_shutdown_intel;
- hdev->set_diag = btintel_set_diag_mfg;
hdev->set_bdaddr = btintel_set_bdaddr;
set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks);
- }
- if (id->driver_info & BTUSB_INTEL_NEW) {
- hdev->manufacturer = 2;
- hdev->send = btusb_send_frame_intel;
- hdev->setup = btusb_setup_intel_new;
- hdev->hw_error = btintel_hw_error;
- hdev->set_diag = btintel_set_diag;
- hdev->set_bdaddr = btintel_set_bdaddr;
- set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
- set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
- set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks);
+ if (id->driver_info & BTUSB_INTEL) {
+ hdev->setup = btusb_setup_intel;
+ hdev->shutdown = btusb_shutdown_intel;
+ hdev->set_diag = btintel_set_diag_mfg;
+ } else {
+ hdev->send = btusb_send_frame_intel;
+ hdev->setup = btusb_setup_intel_new;
+ hdev->hw_error = btintel_hw_error;
+ hdev->set_diag = btintel_set_diag;
+ }
}
if (id->driver_info & BTUSB_MARVELL)
--
2.19.1.1215.g8438c0b245-goog
^ permalink raw reply related
* [PATCH v2 3/5] Bluetooth: Reset Bluetooth chip after multiple command timeouts
From: Rajat Jain @ 2018-11-19 23:04 UTC (permalink / raw)
To: Marcel Holtmann, Johan Hedberg, Greg Kroah-Hartman,
David S. Miller, Dmitry Torokhov, Rajat Jain, Alex Hung,
linux-bluetooth, linux-kernel, linux-usb, netdev
Cc: rajatxjain, dtor, raghuram.hegde, chethan.tumkur.narayan,
sukumar.ghorai
In-Reply-To: <20181119230409.258121-1-rajatja@google.com>
Add a quirk and a hook to allow the HCI core to reset the BT chip
if needed (after a number of timed out commands). Use that new hook to
initiate BT chip reset if the controller fails to respond to certain
number of commands (currently 5) including the HCI reset commands.
This is done based on a newly introduced quirk. This is done based
on some initial work by Intel.
Signed-off-by: Rajat Jain <rajatja@google.com>
---
v2: same as v1
include/net/bluetooth/hci.h | 8 ++++++++
include/net/bluetooth/hci_core.h | 2 ++
net/bluetooth/hci_core.c | 15 +++++++++++++--
3 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index c36dc1e20556..af02fa5ffe54 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -192,6 +192,14 @@ enum {
*
*/
HCI_QUIRK_NON_PERSISTENT_SETUP,
+
+ /* When this quirk is set, hw_reset() would be run to reset the
+ * hardware, after a certain number of commands (currently 5)
+ * time out because the device fails to respond.
+ *
+ * This quirk should be set before hci_register_dev is called.
+ */
+ HCI_QUIRK_HW_RESET_ON_TIMEOUT,
};
/* HCI device flags */
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index e5ea633ea368..b86218304b80 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -313,6 +313,7 @@ struct hci_dev {
unsigned int acl_cnt;
unsigned int sco_cnt;
unsigned int le_cnt;
+ unsigned int timeout_cnt;
unsigned int acl_mtu;
unsigned int sco_mtu;
@@ -437,6 +438,7 @@ struct hci_dev {
int (*post_init)(struct hci_dev *hdev);
int (*set_diag)(struct hci_dev *hdev, bool enable);
int (*set_bdaddr)(struct hci_dev *hdev, const bdaddr_t *bdaddr);
+ void (*hw_reset)(struct hci_dev *hdev);
};
#define HCI_PHY_HANDLE(handle) (handle & 0xff)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 7352fe85674b..ab3a6a8b7ba6 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2569,13 +2569,24 @@ static void hci_cmd_timeout(struct work_struct *work)
struct hci_dev *hdev = container_of(work, struct hci_dev,
cmd_timer.work);
+ hdev->timeout_cnt++;
if (hdev->sent_cmd) {
struct hci_command_hdr *sent = (void *) hdev->sent_cmd->data;
u16 opcode = __le16_to_cpu(sent->opcode);
- bt_dev_err(hdev, "command 0x%4.4x tx timeout", opcode);
+ bt_dev_err(hdev, "command 0x%4.4x tx timeout (cnt = %u)",
+ opcode, hdev->timeout_cnt);
} else {
- bt_dev_err(hdev, "command tx timeout");
+ bt_dev_err(hdev, "command tx timeout (cnt = %u)",
+ hdev->timeout_cnt);
+ }
+
+ if (test_bit(HCI_QUIRK_HW_RESET_ON_TIMEOUT, &hdev->quirks) &&
+ hdev->timeout_cnt >= 5) {
+ hdev->timeout_cnt = 0;
+ if (hdev->hw_reset)
+ hdev->hw_reset(hdev);
+ return;
}
atomic_set(&hdev->cmd_cnt, 1);
--
2.19.1.1215.g8438c0b245-goog
^ permalink raw reply related
* [PATCH iproute2-next 8/8] tc: gred: allow controlling and dumping per-DP RED flags
From: Jakub Kicinski @ 2018-11-19 23:03 UTC (permalink / raw)
To: dsahern, stephen; +Cc: oss-drivers, netdev, Jakub Kicinski
In-Reply-To: <20181119230335.11771-1-jakub.kicinski@netronome.com>
Kernel now support setting ECN and HARDDROP flags per-virtual
queue. Allow users to tweak the settings, and print them on
dump.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
---
tc/q_gred.c | 28 +++++++++++++++++++++++++---
1 file changed, 25 insertions(+), 3 deletions(-)
diff --git a/tc/q_gred.c b/tc/q_gred.c
index dfa3252bc2a8..e297b866c76e 100644
--- a/tc/q_gred.c
+++ b/tc/q_gred.c
@@ -40,7 +40,7 @@ static void explain(void)
fprintf(stderr, " default DEFAULT_VQ [ grio ] [ limit BYTES ] [ecn] [harddrop]\n");
fprintf(stderr, " tc qdisc change ... gred vq VQ [ prio VALUE ] limit BYTES\n");
fprintf(stderr, " min BYTES max BYTES avpkt BYTES [ burst PACKETS ]\n");
- fprintf(stderr, " [ probability PROBABILITY ] [ bandwidth KBPS ]\n");
+ fprintf(stderr, " [ probability PROBABILITY ] [ bandwidth KBPS ] [ecn] [harddrop]\n");
}
static int init_gred(struct qdisc_util *qu, int argc, char **argv,
@@ -121,15 +121,16 @@ static int init_gred(struct qdisc_util *qu, int argc, char **argv,
*/
static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev)
{
+ struct rtattr *tail, *entry, *vqs;
int ok = 0;
struct tc_gred_qopt opt = { 0 };
unsigned int burst = 0;
unsigned int avpkt = 0;
+ unsigned int flags = 0;
double probability = 0.02;
unsigned int rate = 0;
int parm;
__u8 sbuf[256];
- struct rtattr *tail;
__u32 max_P;
opt.DP = MAX_DPs;
@@ -212,6 +213,10 @@ static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct n
return -1;
}
ok++;
+ } else if (strcmp(*argv, "ecn") == 0) {
+ flags |= TC_RED_ECN;
+ } else if (strcmp(*argv, "harddrop") == 0) {
+ flags |= TC_RED_HARDDROP;
} else if (strcmp(*argv, "help") == 0) {
explain();
return -1;
@@ -265,11 +270,20 @@ static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct n
addattr_l(n, 1024, TCA_GRED_STAB, sbuf, 256);
max_P = probability * pow(2, 32);
addattr32(n, 1024, TCA_GRED_MAX_P, max_P);
+
+ vqs = addattr_nest(n, 1024, TCA_GRED_VQ_LIST);
+ entry = addattr_nest(n, 1024, TCA_GRED_VQ_ENTRY);
+ addattr32(n, 1024, TCA_GRED_VQ_DP, opt.DP);
+ addattr32(n, 1024, TCA_GRED_VQ_FLAGS, flags);
+ addattr_nest_end(n, entry);
+ addattr_nest_end(n, vqs);
+
addattr_nest_end(n, tail);
return 0;
}
struct tc_gred_info {
+ bool flags_present;
__u64 bytes;
__u32 packets;
__u32 backlog;
@@ -279,6 +293,7 @@ struct tc_gred_info {
__u32 forced_mark;
__u32 pdrop;
__u32 other;
+ __u32 flags;
};
static void
@@ -345,6 +360,10 @@ gred_parse_vqs(struct tc_gred_info *info, struct rtattr *vqs)
if (tb[TCA_GRED_VQ_STAT_OTHER])
info[dp].other =
rta_getattr_u32(tb[TCA_GRED_VQ_STAT_OTHER]);
+ info[dp].flags_present = !!tb[TCA_GRED_VQ_FLAGS];
+ if (tb[TCA_GRED_VQ_FLAGS])
+ info[dp].flags =
+ rta_getattr_u32(tb[TCA_GRED_VQ_FLAGS]);
}
}
@@ -437,7 +456,7 @@ static int gred_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
return -1;
}
- if (tb[TCA_GRED_VQ_LIST] && show_stats) {
+ if (tb[TCA_GRED_VQ_LIST]) {
gred_parse_vqs(infos, tb[TCA_GRED_VQ_LIST]);
vq_info = true;
}
@@ -480,6 +499,9 @@ static int gred_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
print_string(PRINT_FP, NULL, "max %s ",
sprint_size(qopt->qth_max, b1));
+ if (infos[i].flags_present)
+ tc_red_print_flags(infos[i].flags);
+
if (show_details) {
print_uint(PRINT_ANY, "ewma", "ewma %u ", qopt->Wlog);
if (max_p)
--
2.17.1
^ permalink raw reply related
* [PATCH iproute2-next 7/8] tc: gred: support controlling RED flags
From: Jakub Kicinski @ 2018-11-19 23:03 UTC (permalink / raw)
To: dsahern, stephen; +Cc: oss-drivers, netdev, Jakub Kicinski
In-Reply-To: <20181119230335.11771-1-jakub.kicinski@netronome.com>
Kernel GRED qdisc supports ECN marking, and the harddrop flag
but setting and dumping this flag is not possible with iproute2.
Add the support.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
---
bash-completion/tc | 2 +-
tc/q_gred.c | 8 +++++++-
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/bash-completion/tc b/bash-completion/tc
index 29bca5d9354d..007e1c2e30bf 100644
--- a/bash-completion/tc
+++ b/bash-completion/tc
@@ -302,7 +302,7 @@ _tc_qdisc_options()
;;
gred)
_tc_once_attr 'setup vqs default grio vq prio limit min max avpkt \
- burst probability bandwidth'
+ burst probability bandwidth ecn harddrop'
return 0
;;
hhf)
diff --git a/tc/q_gred.c b/tc/q_gred.c
index fda41a5704a9..dfa3252bc2a8 100644
--- a/tc/q_gred.c
+++ b/tc/q_gred.c
@@ -37,7 +37,7 @@
static void explain(void)
{
fprintf(stderr, "Usage: tc qdisc { add | replace | change } ... gred setup vqs NUMBER\n");
- fprintf(stderr, " default DEFAULT_VQ [ grio ] [ limit BYTES ]\n");
+ fprintf(stderr, " default DEFAULT_VQ [ grio ] [ limit BYTES ] [ecn] [harddrop]\n");
fprintf(stderr, " tc qdisc change ... gred vq VQ [ prio VALUE ] limit BYTES\n");
fprintf(stderr, " min BYTES max BYTES avpkt BYTES [ burst PACKETS ]\n");
fprintf(stderr, " [ probability PROBABILITY ] [ bandwidth KBPS ]\n");
@@ -87,6 +87,10 @@ static int init_gred(struct qdisc_util *qu, int argc, char **argv,
fprintf(stderr, "Illegal \"limit\"\n");
return -1;
}
+ } else if (strcmp(*argv, "ecn") == 0) {
+ opt.flags |= TC_RED_ECN;
+ } else if (strcmp(*argv, "harddrop") == 0) {
+ opt.flags |= TC_RED_HARDDROP;
} else if (strcmp(*argv, "help") == 0) {
explain();
return -1;
@@ -452,6 +456,8 @@ static int gred_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
sprint_size(*limit, b1));
}
+ tc_red_print_flags(sopt->flags);
+
open_json_array(PRINT_JSON, "vqs");
for (i = 0; i < MAX_DPs; i++, qopt++) {
if (qopt->DP >= MAX_DPs)
--
2.17.1
^ permalink raw reply related
* [PATCH iproute2-next 6/8] tc: gred: use extended stats if available
From: Jakub Kicinski @ 2018-11-19 23:03 UTC (permalink / raw)
To: dsahern, stephen; +Cc: oss-drivers, netdev, Jakub Kicinski
In-Reply-To: <20181119230335.11771-1-jakub.kicinski@netronome.com>
Use the extended attributes with extra and better stats, when
possible.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
---
tc/q_gred.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 114 insertions(+), 8 deletions(-)
diff --git a/tc/q_gred.c b/tc/q_gred.c
index 501437bc5abe..fda41a5704a9 100644
--- a/tc/q_gred.c
+++ b/tc/q_gred.c
@@ -265,8 +265,90 @@ static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct n
return 0;
}
-static void gred_print_stats(struct tc_gred_qopt *qopt)
+struct tc_gred_info {
+ __u64 bytes;
+ __u32 packets;
+ __u32 backlog;
+ __u32 prob_drop;
+ __u32 prob_mark;
+ __u32 forced_drop;
+ __u32 forced_mark;
+ __u32 pdrop;
+ __u32 other;
+};
+
+static void
+gred_parse_vqs(struct tc_gred_info *info, struct rtattr *vqs)
{
+ int rem = RTA_PAYLOAD(vqs);
+ unsigned int offset = 0;
+
+ while (rem > offset) {
+ struct rtattr *tb_entry[TCA_GRED_VQ_ENTRY_MAX + 1] = {};
+ struct rtattr *tb[TCA_GRED_VQ_MAX + 1] = {};
+ struct rtattr *entry;
+ unsigned int len;
+ unsigned int dp;
+
+ entry = RTA_DATA(vqs) + offset;
+
+ parse_rtattr(tb_entry, TCA_GRED_VQ_ENTRY_MAX, entry,
+ rem - offset);
+ len = RTA_LENGTH(RTA_PAYLOAD(entry));
+ offset += len;
+
+ if (!tb_entry[TCA_GRED_VQ_ENTRY]) {
+ fprintf(stderr,
+ "ERROR: Failed to parse Virtual Queue entry\n");
+ continue;
+ }
+
+ parse_rtattr_nested(tb, TCA_GRED_VQ_MAX,
+ tb_entry[TCA_GRED_VQ_ENTRY]);
+
+ if (!tb[TCA_GRED_VQ_DP]) {
+ fprintf(stderr,
+ "ERROR: Virtual Queue without DP attribute\n");
+ continue;
+ }
+
+ dp = rta_getattr_u32(tb[TCA_GRED_VQ_DP]);
+
+ if (tb[TCA_GRED_VQ_STAT_BYTES])
+ info[dp].bytes =
+ rta_getattr_u32(tb[TCA_GRED_VQ_STAT_BYTES]);
+ if (tb[TCA_GRED_VQ_STAT_PACKETS])
+ info[dp].packets =
+ rta_getattr_u32(tb[TCA_GRED_VQ_STAT_PACKETS]);
+ if (tb[TCA_GRED_VQ_STAT_BACKLOG])
+ info[dp].backlog =
+ rta_getattr_u32(tb[TCA_GRED_VQ_STAT_BACKLOG]);
+ if (tb[TCA_GRED_VQ_STAT_PROB_DROP])
+ info[dp].prob_drop =
+ rta_getattr_u32(tb[TCA_GRED_VQ_STAT_PROB_DROP]);
+ if (tb[TCA_GRED_VQ_STAT_PROB_MARK])
+ info[dp].prob_mark =
+ rta_getattr_u32(tb[TCA_GRED_VQ_STAT_PROB_MARK]);
+ if (tb[TCA_GRED_VQ_STAT_FORCED_DROP])
+ info[dp].forced_drop =
+ rta_getattr_u32(tb[TCA_GRED_VQ_STAT_FORCED_DROP]);
+ if (tb[TCA_GRED_VQ_STAT_FORCED_MARK])
+ info[dp].forced_mark =
+ rta_getattr_u32(tb[TCA_GRED_VQ_STAT_FORCED_MARK]);
+ if (tb[TCA_GRED_VQ_STAT_PDROP])
+ info[dp].pdrop =
+ rta_getattr_u32(tb[TCA_GRED_VQ_STAT_PDROP]);
+ if (tb[TCA_GRED_VQ_STAT_OTHER])
+ info[dp].other =
+ rta_getattr_u32(tb[TCA_GRED_VQ_STAT_OTHER]);
+ }
+}
+
+static void
+gred_print_stats(struct tc_gred_info *info, struct tc_gred_qopt *qopt)
+{
+ __u64 bytes = info ? info->bytes : qopt->bytesin;
+
SPRINT_BUF(b1);
if (!is_json_context())
@@ -283,25 +365,44 @@ static void gred_print_stats(struct tc_gred_qopt *qopt)
if (!is_json_context())
printf("\n Dropped packets: ");
- print_uint(PRINT_ANY, "forced_drop", "forced %u ", qopt->forced);
- print_uint(PRINT_ANY, "prob_drop", "early %u ", qopt->early);
- print_uint(PRINT_ANY, "pdrop", "pdrop %u ", qopt->pdrop);
- print_uint(PRINT_ANY, "other", "other %u ", qopt->other);
+ if (info) {
+ print_uint(PRINT_ANY, "forced_drop", "forced %u ",
+ info->forced_drop);
+ print_uint(PRINT_ANY, "prob_drop", "early %u ",
+ info->prob_drop);
+ print_uint(PRINT_ANY, "pdrop", "pdrop %u ", info->pdrop);
+ print_uint(PRINT_ANY, "other", "other %u ", info->other);
+
+ if (!is_json_context())
+ printf("\n Marked packets: ");
+ print_uint(PRINT_ANY, "forced_mark", "forced %u ",
+ info->forced_mark);
+ print_uint(PRINT_ANY, "prob_mark", "early %u ",
+ info->prob_mark);
+ } else {
+ print_uint(PRINT_ANY, "forced_drop", "forced %u ",
+ qopt->forced);
+ print_uint(PRINT_ANY, "prob_drop", "early %u ", qopt->early);
+ print_uint(PRINT_ANY, "pdrop", "pdrop %u ", qopt->pdrop);
+ print_uint(PRINT_ANY, "other", "other %u ", qopt->other);
+ }
if (!is_json_context())
printf("\n Total packets: ");
print_uint(PRINT_ANY, "packets", "%u ", qopt->packets);
- print_uint(PRINT_JSON, "bytes", NULL, qopt->bytesin);
- print_string(PRINT_FP, NULL, "(%s) ", sprint_size(qopt->bytesin, b1));
+ print_uint(PRINT_JSON, "bytes", NULL, bytes);
+ print_string(PRINT_FP, NULL, "(%s) ", sprint_size(bytes, b1));
}
static int gred_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
{
+ struct tc_gred_info infos[MAX_DPs] = {};
struct rtattr *tb[TCA_GRED_MAX + 1];
struct tc_gred_sopt *sopt;
struct tc_gred_qopt *qopt;
+ bool vq_info = false;
__u32 *max_p = NULL;
__u32 *limit = NULL;
unsigned int i;
@@ -332,6 +433,11 @@ static int gred_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
return -1;
}
+ if (tb[TCA_GRED_VQ_LIST] && show_stats) {
+ gred_parse_vqs(infos, tb[TCA_GRED_VQ_LIST]);
+ vq_info = true;
+ }
+
print_uint(PRINT_ANY, "dp_cnt", "vqs %u ", sopt->DPs);
print_uint(PRINT_ANY, "dp_default", "default %u ", sopt->def_DP);
@@ -381,7 +487,7 @@ static int gred_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
qopt->Scell_log);
}
if (show_stats)
- gred_print_stats(qopt);
+ gred_print_stats(vq_info ? &infos[i] : NULL, qopt);
close_json_object();
}
close_json_array(PRINT_JSON, "vqs");
--
2.17.1
^ permalink raw reply related
* [PATCH iproute2-next 5/8] tc: gred: separate out stats printing
From: Jakub Kicinski @ 2018-11-19 23:03 UTC (permalink / raw)
To: dsahern, stephen; +Cc: oss-drivers, netdev, Jakub Kicinski
In-Reply-To: <20181119230335.11771-1-jakub.kicinski@netronome.com>
Printing GRED statistics is long and deserves a function on its own.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
---
tc/q_gred.c | 67 +++++++++++++++++++++++++++--------------------------
1 file changed, 34 insertions(+), 33 deletions(-)
diff --git a/tc/q_gred.c b/tc/q_gred.c
index 768b77ba3b0d..501437bc5abe 100644
--- a/tc/q_gred.c
+++ b/tc/q_gred.c
@@ -265,6 +265,38 @@ static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct n
return 0;
}
+static void gred_print_stats(struct tc_gred_qopt *qopt)
+{
+ SPRINT_BUF(b1);
+
+ if (!is_json_context())
+ printf("\n Queue size: ");
+
+ print_uint(PRINT_JSON, "qave", NULL, qopt->qave);
+ print_string(PRINT_FP, NULL, "average %s ",
+ sprint_size(qopt->qave, b1));
+
+ print_uint(PRINT_JSON, "backlog", NULL, qopt->backlog);
+ print_string(PRINT_FP, NULL, "current %s ",
+ sprint_size(qopt->backlog, b1));
+
+ if (!is_json_context())
+ printf("\n Dropped packets: ");
+
+ print_uint(PRINT_ANY, "forced_drop", "forced %u ", qopt->forced);
+ print_uint(PRINT_ANY, "prob_drop", "early %u ", qopt->early);
+ print_uint(PRINT_ANY, "pdrop", "pdrop %u ", qopt->pdrop);
+ print_uint(PRINT_ANY, "other", "other %u ", qopt->other);
+
+ if (!is_json_context())
+ printf("\n Total packets: ");
+
+ print_uint(PRINT_ANY, "packets", "%u ", qopt->packets);
+
+ print_uint(PRINT_JSON, "bytes", NULL, qopt->bytesin);
+ print_string(PRINT_FP, NULL, "(%s) ", sprint_size(qopt->bytesin, b1));
+}
+
static int gred_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
{
struct rtattr *tb[TCA_GRED_MAX + 1];
@@ -348,39 +380,8 @@ static int gred_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
print_uint(PRINT_ANY, "Scell_log", "Scell_log %u ",
qopt->Scell_log);
}
- if (show_stats) {
- if (!is_json_context())
- printf("\n Queue size: ");
-
- print_uint(PRINT_JSON, "qave", NULL, qopt->qave);
- print_string(PRINT_FP, NULL, "average %s ",
- sprint_size(qopt->qave, b1));
-
- print_uint(PRINT_JSON, "backlog", NULL, qopt->backlog);
- print_string(PRINT_FP, NULL, "current %s ",
- sprint_size(qopt->backlog, b1));
-
- if (!is_json_context())
- printf("\n Dropped packets: ");
-
- print_uint(PRINT_ANY, "forced_drop", "forced %u ",
- qopt->forced);
- print_uint(PRINT_ANY, "prob_drop", "early %u ",
- qopt->early);
- print_uint(PRINT_ANY, "pdrop", "pdrop %u ",
- qopt->pdrop);
- print_uint(PRINT_ANY, "other", "other %u ",
- qopt->other);
-
- if (!is_json_context())
- printf("\n Total packets: ");
-
- print_uint(PRINT_ANY, "packets", "%u ", qopt->packets);
-
- print_uint(PRINT_JSON, "bytes", NULL, qopt->bytesin);
- print_string(PRINT_FP, NULL, "(%s) ",
- sprint_size(qopt->bytesin, b1));
- }
+ if (show_stats)
+ gred_print_stats(qopt);
close_json_object();
}
close_json_array(PRINT_JSON, "vqs");
--
2.17.1
^ permalink raw reply related
* [PATCH iproute2-next 4/8] tc: gred: jsonify GRED output
From: Jakub Kicinski @ 2018-11-19 23:03 UTC (permalink / raw)
To: dsahern, stephen; +Cc: oss-drivers, netdev, Jakub Kicinski
In-Reply-To: <20181119230335.11771-1-jakub.kicinski@netronome.com>
Make GRED dump JSON-compatible.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
---
tc/q_gred.c | 105 ++++++++++++++++++++++++++++++++++++----------------
1 file changed, 74 insertions(+), 31 deletions(-)
diff --git a/tc/q_gred.c b/tc/q_gred.c
index 80a9ccbbd3cb..768b77ba3b0d 100644
--- a/tc/q_gred.c
+++ b/tc/q_gred.c
@@ -275,8 +275,6 @@ static int gred_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
unsigned int i;
SPRINT_BUF(b1);
- SPRINT_BUF(b2);
- SPRINT_BUF(b3);
if (opt == NULL)
return 0;
@@ -302,45 +300,90 @@ static int gred_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
return -1;
}
- fprintf(f, "vqs %u default %u %s",
- sopt->DPs,
- sopt->def_DP,
- sopt->grio ? "grio " : "");
+ print_uint(PRINT_ANY, "dp_cnt", "vqs %u ", sopt->DPs);
+ print_uint(PRINT_ANY, "dp_default", "default %u ", sopt->def_DP);
- if (limit)
- fprintf(f, "limit %s ",
- sprint_size(*limit, b1));
+ if (sopt->grio)
+ print_bool(PRINT_ANY, "grio", "grio ", true);
+ else
+ print_bool(PRINT_ANY, "grio", NULL, false);
+
+ if (limit) {
+ print_uint(PRINT_JSON, "limit", NULL, *limit);
+ print_string(PRINT_FP, NULL, "limit %s ",
+ sprint_size(*limit, b1));
+ }
+ open_json_array(PRINT_JSON, "vqs");
for (i = 0; i < MAX_DPs; i++, qopt++) {
- if (qopt->DP >= MAX_DPs) continue;
- fprintf(f, "\n vq %u prio %hhu limit %s min %s max %s ",
- qopt->DP,
- qopt->prio,
- sprint_size(qopt->limit, b1),
- sprint_size(qopt->qth_min, b2),
- sprint_size(qopt->qth_max, b3));
+ if (qopt->DP >= MAX_DPs)
+ continue;
+
+ open_json_object(NULL);
+
+ print_uint(PRINT_ANY, "vq", "\n vq %u ", qopt->DP);
+ print_hhu(PRINT_ANY, "prio", "prio %hhu ", qopt->prio);
+
+ print_uint(PRINT_JSON, "limit", NULL, qopt->limit);
+ print_string(PRINT_FP, NULL, "limit %s ",
+ sprint_size(qopt->limit, b1));
+
+ print_uint(PRINT_JSON, "min", NULL, qopt->qth_min);
+ print_string(PRINT_FP, NULL, "min %s ",
+ sprint_size(qopt->qth_min, b1));
+
+ print_uint(PRINT_JSON, "max", NULL, qopt->qth_max);
+ print_string(PRINT_FP, NULL, "max %s ",
+ sprint_size(qopt->qth_max, b1));
+
if (show_details) {
- fprintf(f, "ewma %u ", qopt->Wlog);
+ print_uint(PRINT_ANY, "ewma", "ewma %u ", qopt->Wlog);
if (max_p)
- fprintf(f, "probability %lg ", max_p[i] / pow(2, 32));
+ print_float(PRINT_ANY, "probability",
+ "probability %lg ",
+ max_p[i] / pow(2, 32));
else
- fprintf(f, "Plog %u ", qopt->Plog);
- fprintf(f, "Scell_log %u ", qopt->Scell_log);
+ print_uint(PRINT_ANY, "Plog", "Plog %u ",
+ qopt->Plog);
+ print_uint(PRINT_ANY, "Scell_log", "Scell_log %u ",
+ qopt->Scell_log);
}
if (show_stats) {
- fprintf(f, "\n Queue size: average %s current %s ",
- sprint_size(qopt->qave, b1),
- sprint_size(qopt->backlog, b2));
- fprintf(f, "\n Dropped packets: forced %u early %u pdrop %u other %u ",
- qopt->forced,
- qopt->early,
- qopt->pdrop,
- qopt->other);
- fprintf(f, "\n Total packets: %u (%s) ",
- qopt->packets,
- sprint_size(qopt->bytesin, b1));
+ if (!is_json_context())
+ printf("\n Queue size: ");
+
+ print_uint(PRINT_JSON, "qave", NULL, qopt->qave);
+ print_string(PRINT_FP, NULL, "average %s ",
+ sprint_size(qopt->qave, b1));
+
+ print_uint(PRINT_JSON, "backlog", NULL, qopt->backlog);
+ print_string(PRINT_FP, NULL, "current %s ",
+ sprint_size(qopt->backlog, b1));
+
+ if (!is_json_context())
+ printf("\n Dropped packets: ");
+
+ print_uint(PRINT_ANY, "forced_drop", "forced %u ",
+ qopt->forced);
+ print_uint(PRINT_ANY, "prob_drop", "early %u ",
+ qopt->early);
+ print_uint(PRINT_ANY, "pdrop", "pdrop %u ",
+ qopt->pdrop);
+ print_uint(PRINT_ANY, "other", "other %u ",
+ qopt->other);
+
+ if (!is_json_context())
+ printf("\n Total packets: ");
+
+ print_uint(PRINT_ANY, "packets", "%u ", qopt->packets);
+
+ print_uint(PRINT_JSON, "bytes", NULL, qopt->bytesin);
+ print_string(PRINT_FP, NULL, "(%s) ",
+ sprint_size(qopt->bytesin, b1));
}
+ close_json_object();
}
+ close_json_array(PRINT_JSON, "vqs");
return 0;
}
--
2.17.1
^ permalink raw reply related
* [PATCH iproute2-next 3/8] tc: move RED flag printing to helper
From: Jakub Kicinski @ 2018-11-19 23:03 UTC (permalink / raw)
To: dsahern, stephen; +Cc: oss-drivers, netdev, Jakub Kicinski
In-Reply-To: <20181119230335.11771-1-jakub.kicinski@netronome.com>
Number of qdiscs use the same set of flags to control shared RED
implementation. Add a helper for printing those flags.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
---
tc/q_choke.c | 3 +--
tc/q_red.c | 14 ++------------
tc/q_sfq.c | 3 +--
tc/tc_red.c | 20 ++++++++++++++++++++
tc/tc_red.h | 1 +
5 files changed, 25 insertions(+), 16 deletions(-)
diff --git a/tc/q_choke.c b/tc/q_choke.c
index b269b1338b6d..1353c80c806b 100644
--- a/tc/q_choke.c
+++ b/tc/q_choke.c
@@ -188,8 +188,7 @@ static int choke_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
fprintf(f, "limit %up min %up max %up ",
qopt->limit, qopt->qth_min, qopt->qth_max);
- if (qopt->flags & TC_RED_ECN)
- fprintf(f, "ecn ");
+ tc_red_print_flags(qopt->flags);
if (show_details) {
fprintf(f, "ewma %u ", qopt->Wlog);
diff --git a/tc/q_red.c b/tc/q_red.c
index 49fd4ac80513..3b3a12041989 100644
--- a/tc/q_red.c
+++ b/tc/q_red.c
@@ -189,18 +189,8 @@ static int red_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
print_uint(PRINT_JSON, "max", NULL, qopt->qth_max);
print_string(PRINT_FP, NULL, "max %s ", sprint_size(qopt->qth_max, b3));
- if (qopt->flags & TC_RED_ECN)
- print_bool(PRINT_ANY, "ecn", "ecn ", true);
- else
- print_bool(PRINT_ANY, "ecn", NULL, false);
- if (qopt->flags & TC_RED_HARDDROP)
- print_bool(PRINT_ANY, "harddrop", "harddrop ", true);
- else
- print_bool(PRINT_ANY, "harddrop", NULL, false);
- if (qopt->flags & TC_RED_ADAPTATIVE)
- print_bool(PRINT_ANY, "adaptive", "adaptive ", true);
- else
- print_bool(PRINT_ANY, "adaptive", NULL, false);
+ tc_red_print_flags(qopt->flags);
+
if (show_details) {
print_uint(PRINT_ANY, "ewma", "ewma %u ", qopt->Wlog);
if (max_P)
diff --git a/tc/q_sfq.c b/tc/q_sfq.c
index 6a1d853b7c93..eee31ec54d33 100644
--- a/tc/q_sfq.c
+++ b/tc/q_sfq.c
@@ -235,8 +235,7 @@ static int sfq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
sprint_size(qopt_ext->qth_min, b2),
sprint_size(qopt_ext->qth_max, b3),
qopt_ext->max_P / pow(2, 32));
- if (qopt_ext->flags & TC_RED_ECN)
- fprintf(f, "ecn ");
+ tc_red_print_flags(qopt_ext->flags);
if (show_stats) {
fprintf(f, "\n prob_mark %u prob_mark_head %u prob_drop %u",
qopt_ext->stats.prob_mark,
diff --git a/tc/tc_red.c b/tc/tc_red.c
index 178fe088f732..3ce3ca4287d3 100644
--- a/tc/tc_red.c
+++ b/tc/tc_red.c
@@ -20,7 +20,9 @@
#include <arpa/inet.h>
#include <string.h>
+#include "utils.h"
#include "tc_core.h"
+#include "tc_util.h"
#include "tc_red.h"
/*
@@ -97,3 +99,21 @@ int tc_red_eval_idle_damping(int Wlog, unsigned int avpkt, unsigned int bps, __u
sbuf[255] = 31;
return clog;
}
+
+void tc_red_print_flags(__u32 flags)
+{
+ if (flags & TC_RED_ECN)
+ print_bool(PRINT_ANY, "ecn", "ecn ", true);
+ else
+ print_bool(PRINT_ANY, "ecn", NULL, false);
+
+ if (flags & TC_RED_HARDDROP)
+ print_bool(PRINT_ANY, "harddrop", "harddrop ", true);
+ else
+ print_bool(PRINT_ANY, "harddrop", NULL, false);
+
+ if (flags & TC_RED_ADAPTATIVE)
+ print_bool(PRINT_ANY, "adaptive", "adaptive ", true);
+ else
+ print_bool(PRINT_ANY, "adaptive", NULL, false);
+}
diff --git a/tc/tc_red.h b/tc/tc_red.h
index 6c6e6b039732..3882c8310d76 100644
--- a/tc/tc_red.h
+++ b/tc/tc_red.h
@@ -6,5 +6,6 @@ int tc_red_eval_P(unsigned qmin, unsigned qmax, double prob);
int tc_red_eval_ewma(unsigned qmin, unsigned burst, unsigned avpkt);
int tc_red_eval_idle_damping(int wlog, unsigned avpkt, unsigned bandwidth,
__u8 *sbuf);
+void tc_red_print_flags(__u32 flags);
#endif
--
2.17.1
^ permalink raw reply related
* [PATCH iproute2-next 2/8] json: add %hhu helpers
From: Jakub Kicinski @ 2018-11-19 23:03 UTC (permalink / raw)
To: dsahern, stephen; +Cc: oss-drivers, netdev, Jakub Kicinski
In-Reply-To: <20181119230335.11771-1-jakub.kicinski@netronome.com>
Add helpers for printing char-size values.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
---
include/json_print.h | 1 +
include/json_writer.h | 2 ++
lib/json_print.c | 1 +
lib/json_writer.c | 11 +++++++++++
4 files changed, 15 insertions(+)
diff --git a/include/json_print.h b/include/json_print.h
index 218da31a73fe..25954070db27 100644
--- a/include/json_print.h
+++ b/include/json_print.h
@@ -64,6 +64,7 @@ _PRINT_FUNC(null, const char*);
_PRINT_FUNC(string, const char*);
_PRINT_FUNC(uint, unsigned int);
_PRINT_FUNC(u64, uint64_t);
+_PRINT_FUNC(hhu, unsigned char);
_PRINT_FUNC(hu, unsigned short);
_PRINT_FUNC(hex, unsigned int);
_PRINT_FUNC(0xhex, unsigned long long int);
diff --git a/include/json_writer.h b/include/json_writer.h
index 0c8831c1136d..354c27541e89 100644
--- a/include/json_writer.h
+++ b/include/json_writer.h
@@ -38,6 +38,7 @@ void jsonw_float_fmt(json_writer_t *self, const char *fmt, double num);
void jsonw_uint(json_writer_t *self, unsigned int number);
void jsonw_u64(json_writer_t *self, uint64_t number);
void jsonw_xint(json_writer_t *self, uint64_t number);
+void jsonw_hhu(json_writer_t *self, unsigned char num);
void jsonw_hu(json_writer_t *self, unsigned short number);
void jsonw_int(json_writer_t *self, int number);
void jsonw_s64(json_writer_t *self, int64_t number);
@@ -52,6 +53,7 @@ void jsonw_float_field(json_writer_t *self, const char *prop, double num);
void jsonw_uint_field(json_writer_t *self, const char *prop, unsigned int num);
void jsonw_u64_field(json_writer_t *self, const char *prop, uint64_t num);
void jsonw_xint_field(json_writer_t *self, const char *prop, uint64_t num);
+void jsonw_hhu_field(json_writer_t *self, const char *prop, unsigned char num);
void jsonw_hu_field(json_writer_t *self, const char *prop, unsigned short num);
void jsonw_int_field(json_writer_t *self, const char *prop, int num);
void jsonw_s64_field(json_writer_t *self, const char *prop, int64_t num);
diff --git a/lib/json_print.c b/lib/json_print.c
index f7ef41c1570f..4f5fef195fde 100644
--- a/lib/json_print.c
+++ b/lib/json_print.c
@@ -118,6 +118,7 @@ void close_json_array(enum output_type type, const char *str)
}
_PRINT_FUNC(int, int);
_PRINT_FUNC(s64, int64_t);
+_PRINT_FUNC(hhu, unsigned char);
_PRINT_FUNC(hu, unsigned short);
_PRINT_FUNC(uint, unsigned int);
_PRINT_FUNC(u64, uint64_t);
diff --git a/lib/json_writer.c b/lib/json_writer.c
index 68890b34ee92..46eff6ad9828 100644
--- a/lib/json_writer.c
+++ b/lib/json_writer.c
@@ -211,6 +211,11 @@ void jsonw_float(json_writer_t *self, double num)
jsonw_printf(self, "%g", num);
}
+void jsonw_hhu(json_writer_t *self, unsigned char num)
+{
+ jsonw_printf(self, "%hhu", num);
+}
+
void jsonw_hu(json_writer_t *self, unsigned short num)
{
jsonw_printf(self, "%hu", num);
@@ -288,6 +293,12 @@ void jsonw_xint_field(json_writer_t *self, const char *prop, uint64_t num)
jsonw_xint(self, num);
}
+void jsonw_hhu_field(json_writer_t *self, const char *prop, unsigned char num)
+{
+ jsonw_name(self, prop);
+ jsonw_hhu(self, num);
+}
+
void jsonw_hu_field(json_writer_t *self, const char *prop, unsigned short num)
{
jsonw_name(self, prop);
--
2.17.1
^ permalink raw reply related
* [PATCH iproute2-next 1/8] tc: gred: remove unclear comment
From: Jakub Kicinski @ 2018-11-19 23:03 UTC (permalink / raw)
To: dsahern, stephen; +Cc: oss-drivers, netdev, Jakub Kicinski
In-Reply-To: <20181119230335.11771-1-jakub.kicinski@netronome.com>
The comment about providing a proper message seems similar to
the comment in the kernel which says:
/* hack -- fix at some point with proper message
This is how we indicate to tc that there is no VQ
at this DP */
it's unclear what that message would be, and whether it's needed.
Remove the confusing comment.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
---
tc/q_gred.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/tc/q_gred.c b/tc/q_gred.c
index e63fac72a883..80a9ccbbd3cb 100644
--- a/tc/q_gred.c
+++ b/tc/q_gred.c
@@ -302,8 +302,6 @@ static int gred_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
return -1;
}
-/* Bad hack! should really return a proper message as shown above*/
-
fprintf(f, "vqs %u default %u %s",
sopt->DPs,
sopt->def_DP,
--
2.17.1
^ permalink raw reply related
* [PATCH iproute2-next 0/8] tc: gred: JSON-ify and support per-vq config
From: Jakub Kicinski @ 2018-11-19 23:03 UTC (permalink / raw)
To: dsahern, stephen; +Cc: oss-drivers, netdev, Jakub Kicinski
Hi!
This set brings GRED support up to date with recent kernel changes.
In particular the new netlink attributes for more fine-grained stats
and per-virtual queue flags.
To make GRED usable in modern deployments the patch set starts with
adding JSON output.
Jakub Kicinski (8):
tc: gred: remove unclear comment
json: add %hhu helpers
tc: move RED flag printing to helper
tc: gred: jsonify GRED output
tc: gred: separate out stats printing
tc: gred: use extended stats if available
tc: gred: support controlling RED flags
tc: gred: allow controlling and dumping per-DP RED flags
bash-completion/tc | 2 +-
include/json_print.h | 1 +
include/json_writer.h | 2 +
lib/json_print.c | 1 +
lib/json_writer.c | 11 ++
tc/q_choke.c | 3 +-
tc/q_gred.c | 250 +++++++++++++++++++++++++++++++++++-------
tc/q_red.c | 14 +--
tc/q_sfq.c | 3 +-
tc/tc_red.c | 20 ++++
tc/tc_red.h | 1 +
11 files changed, 254 insertions(+), 54 deletions(-)
--
2.17.1
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox