Skip to content

Commit 88cab77

Browse files
Jesus Sanchez-Palenciadavem330
authored andcommitted
net/sched: Add HW offloading capability to ETF
Add infra so etf qdisc supports HW offload of time-based transmission. For hw offload, the time sorted list is still used, so packets are dequeued always in order of txtime. Example: $ tc qdisc replace dev enp2s0 parent root handle 100 mqprio num_tc 3 \ map 2 2 1 0 2 2 2 2 2 2 2 2 2 2 2 2 queues 1@0 1@1 2@2 hw 0 $ tc qdisc add dev enp2s0 parent 100:1 etf offload delta 100000 \ clockid CLOCK_REALTIME In this example, the Qdisc will use HW offload for the control of the transmission time through the network adapter. The hrtimer used for packets scheduling inside the qdisc will use the clockid CLOCK_REALTIME as reference and packets leave the Qdisc "delta" (100000) nanoseconds before their transmission time. Because this will be using HW offload and since dynamic clocks are not supported by the hrtimer, the system clock and the PHC clock must be synchronized for this mode to behave as expected. Signed-off-by: Jesus Sanchez-Palencia <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 25db26a commit 88cab77

File tree

3 files changed

+76
-1
lines changed

3 files changed

+76
-1
lines changed

include/net/pkt_sched.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,4 +155,9 @@ struct tc_cbs_qopt_offload {
155155
s32 sendslope;
156156
};
157157

158+
struct tc_etf_qopt_offload {
159+
u8 enable;
160+
s32 queue;
161+
};
162+
158163
#endif

include/uapi/linux/pkt_sched.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -944,6 +944,7 @@ struct tc_etf_qopt {
944944
__s32 clockid;
945945
__u32 flags;
946946
#define TC_ETF_DEADLINE_MODE_ON BIT(0)
947+
#define TC_ETF_OFFLOAD_ON BIT(1)
947948
};
948949

949950
enum {

net/sched/sch_etf.c

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@
2020
#include <net/sock.h>
2121

2222
#define DEADLINE_MODE_IS_ON(x) ((x)->flags & TC_ETF_DEADLINE_MODE_ON)
23+
#define OFFLOAD_IS_ON(x) ((x)->flags & TC_ETF_OFFLOAD_ON)
2324

2425
struct etf_sched_data {
26+
bool offload;
2527
bool deadline_mode;
2628
int clockid;
2729
int queue;
@@ -45,6 +47,9 @@ static inline int validate_input_params(struct tc_etf_qopt *qopt,
4547
* * Dynamic clockids are not supported.
4648
*
4749
* * Delta must be a positive integer.
50+
*
51+
* Also note that for the HW offload case, we must
52+
* expect that system clocks have been synchronized to PHC.
4853
*/
4954
if (qopt->clockid < 0) {
5055
NL_SET_ERR_MSG(extack, "Dynamic clockids are not supported");
@@ -225,6 +230,56 @@ static struct sk_buff *etf_dequeue_timesortedlist(struct Qdisc *sch)
225230
return skb;
226231
}
227232

233+
static void etf_disable_offload(struct net_device *dev,
234+
struct etf_sched_data *q)
235+
{
236+
struct tc_etf_qopt_offload etf = { };
237+
const struct net_device_ops *ops;
238+
int err;
239+
240+
if (!q->offload)
241+
return;
242+
243+
ops = dev->netdev_ops;
244+
if (!ops->ndo_setup_tc)
245+
return;
246+
247+
etf.queue = q->queue;
248+
etf.enable = 0;
249+
250+
err = ops->ndo_setup_tc(dev, TC_SETUP_QDISC_ETF, &etf);
251+
if (err < 0)
252+
pr_warn("Couldn't disable ETF offload for queue %d\n",
253+
etf.queue);
254+
}
255+
256+
static int etf_enable_offload(struct net_device *dev, struct etf_sched_data *q,
257+
struct netlink_ext_ack *extack)
258+
{
259+
const struct net_device_ops *ops = dev->netdev_ops;
260+
struct tc_etf_qopt_offload etf = { };
261+
int err;
262+
263+
if (q->offload)
264+
return 0;
265+
266+
if (!ops->ndo_setup_tc) {
267+
NL_SET_ERR_MSG(extack, "Specified device does not support ETF offload");
268+
return -EOPNOTSUPP;
269+
}
270+
271+
etf.queue = q->queue;
272+
etf.enable = 1;
273+
274+
err = ops->ndo_setup_tc(dev, TC_SETUP_QDISC_ETF, &etf);
275+
if (err < 0) {
276+
NL_SET_ERR_MSG(extack, "Specified device failed to setup ETF hardware offload");
277+
return err;
278+
}
279+
280+
return 0;
281+
}
282+
228283
static int etf_init(struct Qdisc *sch, struct nlattr *opt,
229284
struct netlink_ext_ack *extack)
230285
{
@@ -251,8 +306,9 @@ static int etf_init(struct Qdisc *sch, struct nlattr *opt,
251306

252307
qopt = nla_data(tb[TCA_ETF_PARMS]);
253308

254-
pr_debug("delta %d clockid %d deadline %s\n",
309+
pr_debug("delta %d clockid %d offload %s deadline %s\n",
255310
qopt->delta, qopt->clockid,
311+
OFFLOAD_IS_ON(qopt) ? "on" : "off",
256312
DEADLINE_MODE_IS_ON(qopt) ? "on" : "off");
257313

258314
err = validate_input_params(qopt, extack);
@@ -261,9 +317,16 @@ static int etf_init(struct Qdisc *sch, struct nlattr *opt,
261317

262318
q->queue = sch->dev_queue - netdev_get_tx_queue(dev, 0);
263319

320+
if (OFFLOAD_IS_ON(qopt)) {
321+
err = etf_enable_offload(dev, q, extack);
322+
if (err < 0)
323+
return err;
324+
}
325+
264326
/* Everything went OK, save the parameters used. */
265327
q->delta = qopt->delta;
266328
q->clockid = qopt->clockid;
329+
q->offload = OFFLOAD_IS_ON(qopt);
267330
q->deadline_mode = DEADLINE_MODE_IS_ON(qopt);
268331

269332
switch (q->clockid) {
@@ -326,10 +389,13 @@ static void etf_reset(struct Qdisc *sch)
326389
static void etf_destroy(struct Qdisc *sch)
327390
{
328391
struct etf_sched_data *q = qdisc_priv(sch);
392+
struct net_device *dev = qdisc_dev(sch);
329393

330394
/* Only cancel watchdog if it's been initialized. */
331395
if (q->watchdog.qdisc == sch)
332396
qdisc_watchdog_cancel(&q->watchdog);
397+
398+
etf_disable_offload(dev, q);
333399
}
334400

335401
static int etf_dump(struct Qdisc *sch, struct sk_buff *skb)
@@ -344,6 +410,9 @@ static int etf_dump(struct Qdisc *sch, struct sk_buff *skb)
344410

345411
opt.delta = q->delta;
346412
opt.clockid = q->clockid;
413+
if (q->offload)
414+
opt.flags |= TC_ETF_OFFLOAD_ON;
415+
347416
if (q->deadline_mode)
348417
opt.flags |= TC_ETF_DEADLINE_MODE_ON;
349418

0 commit comments

Comments
 (0)