[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <22a2b146c7443d9303c7051a2ac6b2c52c00b74e.1576515562.git.petrm@mellanox.com>
Date: Mon, 16 Dec 2019 17:01:49 +0000
From: Petr Machata <petrm@...lanox.com>
To: "netdev@...r.kernel.org" <netdev@...r.kernel.org>
CC: Petr Machata <petrm@...lanox.com>,
David Miller <davem@...emloft.net>,
Roopa Prabhu <roopa@...ulusnetworks.com>,
Jakub Kicinski <jakub.kicinski@...ronome.com>,
Roman Mashak <mrv@...atatu.com>,
Ido Schimmel <idosch@...lanox.com>,
Jiri Pirko <jiri@...nulli.us>, Jiri Pirko <jiri@...lanox.com>
Subject: [PATCH net-next mlxsw v1 05/10] net: sch_ets: Make the ETS qdisc
offloadable
Add hooks at appropriate points to make it possible to offload the ETS
Qdisc.
Signed-off-by: Petr Machata <petrm@...lanox.com>
Acked-by: Jiri Pirko <jiri@...lanox.com>
Reviewed-by: Ido Schimmel <idosch@...lanox.com>
---
Notes:
v1 (internal):
- pkt_cls.h: Note that quantum=0 signifies a strict band.
- Fix error path handling when ets_offload_dump() fails.
include/linux/netdevice.h | 1 +
include/net/pkt_cls.h | 31 +++++++++++++
net/sched/sch_ets.c | 95 +++++++++++++++++++++++++++++++++++++++
3 files changed, 127 insertions(+)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 30745068fb39..7a8ed11f5d45 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -849,6 +849,7 @@ enum tc_setup_type {
TC_SETUP_QDISC_GRED,
TC_SETUP_QDISC_TAPRIO,
TC_SETUP_FT,
+ TC_SETUP_QDISC_ETS,
};
/* 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 a7c5d492bc04..47b115e2012a 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -823,4 +823,35 @@ struct tc_root_qopt_offload {
bool ingress;
};
+enum tc_ets_command {
+ TC_ETS_REPLACE,
+ TC_ETS_DESTROY,
+ TC_ETS_STATS,
+ TC_ETS_GRAFT,
+};
+
+struct tc_ets_qopt_offload_replace_params {
+ unsigned int bands;
+ u8 priomap[TC_PRIO_MAX + 1];
+ unsigned int quanta[TCQ_ETS_MAX_BANDS]; /* 0 for strict bands. */
+ unsigned int weights[TCQ_ETS_MAX_BANDS];
+ struct gnet_stats_queue *qstats;
+};
+
+struct tc_ets_qopt_offload_graft_params {
+ u8 band;
+ u32 child_handle;
+};
+
+struct tc_ets_qopt_offload {
+ enum tc_ets_command command;
+ u32 handle;
+ u32 parent;
+ union {
+ struct tc_ets_qopt_offload_replace_params replace_params;
+ struct tc_qopt_offload_stats stats;
+ struct tc_ets_qopt_offload_graft_params graft_params;
+ };
+};
+
#endif
diff --git a/net/sched/sch_ets.c b/net/sched/sch_ets.c
index 3c4fe78af1f9..749c240948ec 100644
--- a/net/sched/sch_ets.c
+++ b/net/sched/sch_ets.c
@@ -76,6 +76,91 @@ static u32 ets_class_id(struct Qdisc *sch, const struct ets_class *cl)
return TC_H_MAKE(sch->handle, band + 1);
}
+static void ets_offload_change(struct Qdisc *sch)
+{
+ struct net_device *dev = qdisc_dev(sch);
+ struct ets_sched *q = qdisc_priv(sch);
+ struct tc_ets_qopt_offload qopt;
+ unsigned int w_psum_prev = 0;
+ unsigned int q_psum = 0;
+ unsigned int q_sum = 0;
+ unsigned int quantum;
+ unsigned int w_psum;
+ unsigned int weight;
+ unsigned int i;
+
+ if (!tc_can_offload(dev) || !dev->netdev_ops->ndo_setup_tc)
+ return;
+
+ qopt.command = TC_ETS_REPLACE;
+ qopt.handle = sch->handle;
+ qopt.parent = sch->parent;
+ qopt.replace_params.bands = q->nbands;
+ qopt.replace_params.qstats = &sch->qstats;
+ memcpy(&qopt.replace_params.priomap,
+ q->prio2band, sizeof(q->prio2band));
+
+ for (i = 0; i < q->nbands; i++)
+ q_sum += q->classes[i].quantum;
+
+ for (i = 0; i < q->nbands; i++) {
+ quantum = q->classes[i].quantum;
+ q_psum += quantum;
+ w_psum = quantum ? q_psum * 100 / q_sum : 0;
+ weight = w_psum - w_psum_prev;
+ w_psum_prev = w_psum;
+
+ qopt.replace_params.quanta[i] = quantum;
+ qopt.replace_params.weights[i] = weight;
+ }
+
+ dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_ETS, &qopt);
+}
+
+static void ets_offload_destroy(struct Qdisc *sch)
+{
+ struct net_device *dev = qdisc_dev(sch);
+ struct tc_ets_qopt_offload qopt;
+
+ if (!tc_can_offload(dev) || !dev->netdev_ops->ndo_setup_tc)
+ return;
+
+ qopt.command = TC_ETS_DESTROY;
+ qopt.handle = sch->handle;
+ qopt.parent = sch->parent;
+ dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_ETS, &qopt);
+}
+
+static void ets_offload_graft(struct Qdisc *sch, struct Qdisc *new,
+ struct Qdisc *old, unsigned long arg,
+ struct netlink_ext_ack *extack)
+{
+ struct net_device *dev = qdisc_dev(sch);
+ struct tc_ets_qopt_offload qopt;
+
+ qopt.command = TC_ETS_GRAFT;
+ qopt.handle = sch->handle;
+ qopt.parent = sch->parent;
+ qopt.graft_params.band = arg - 1;
+ qopt.graft_params.child_handle = new->handle;
+
+ qdisc_offload_graft_helper(dev, sch, new, old, TC_SETUP_QDISC_ETS,
+ &qopt, extack);
+}
+
+static int ets_offload_dump(struct Qdisc *sch)
+{
+ struct tc_ets_qopt_offload qopt;
+
+ qopt.command = TC_ETS_STATS;
+ qopt.handle = sch->handle;
+ qopt.parent = sch->parent;
+ qopt.stats.bstats = &sch->bstats;
+ qopt.stats.qstats = &sch->qstats;
+
+ return qdisc_offload_dump_helper(sch, TC_SETUP_QDISC_ETS, &qopt);
+}
+
static bool ets_class_is_strict(struct ets_sched *q, const struct ets_class *cl)
{
unsigned int band = cl - q->classes;
@@ -128,6 +213,8 @@ static int ets_class_change(struct Qdisc *sch, u32 classid, u32 parentid,
sch_tree_lock(sch);
cl->quantum = quantum;
sch_tree_unlock(sch);
+
+ ets_offload_change(sch);
return 0;
}
@@ -147,6 +234,7 @@ static int ets_class_graft(struct Qdisc *sch, unsigned long arg,
}
*old = qdisc_replace(sch, new, &cl->qdisc);
+ ets_offload_graft(sch, new, *old, arg, extack);
return 0;
}
@@ -563,6 +651,7 @@ static int ets_qdisc_change(struct Qdisc *sch, struct nlattr *opt,
sch_tree_unlock(sch);
+ ets_offload_change(sch);
for (i = q->nbands; i < oldbands; i++) {
qdisc_put(q->classes[i].qdisc);
memset(&q->classes[i], 0, sizeof(q->classes[i]));
@@ -607,6 +696,7 @@ static void ets_qdisc_destroy(struct Qdisc *sch)
struct ets_sched *q = qdisc_priv(sch);
int band;
+ ets_offload_destroy(sch);
tcf_block_put(q->block);
for (band = 0; band < q->nbands; band++)
qdisc_put(q->classes[band].qdisc);
@@ -619,6 +709,11 @@ static int ets_qdisc_dump(struct Qdisc *sch, struct sk_buff *skb)
struct nlattr *nest;
int band;
int prio;
+ int err;
+
+ err = ets_offload_dump(sch);
+ if (err)
+ return err;
opts = nla_nest_start_noflag(skb, TCA_OPTIONS);
if (!opts)
--
2.20.1
Powered by blists - more mailing lists