0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/module.h>
0010 #include <linux/types.h>
0011 #include <linux/kernel.h>
0012 #include <linux/string.h>
0013 #include <linux/errno.h>
0014 #include <linux/errqueue.h>
0015 #include <linux/rbtree.h>
0016 #include <linux/skbuff.h>
0017 #include <linux/posix-timers.h>
0018 #include <net/netlink.h>
0019 #include <net/sch_generic.h>
0020 #include <net/pkt_sched.h>
0021 #include <net/sock.h>
0022
0023 #define DEADLINE_MODE_IS_ON(x) ((x)->flags & TC_ETF_DEADLINE_MODE_ON)
0024 #define OFFLOAD_IS_ON(x) ((x)->flags & TC_ETF_OFFLOAD_ON)
0025 #define SKIP_SOCK_CHECK_IS_SET(x) ((x)->flags & TC_ETF_SKIP_SOCK_CHECK)
0026
0027 struct etf_sched_data {
0028 bool offload;
0029 bool deadline_mode;
0030 bool skip_sock_check;
0031 int clockid;
0032 int queue;
0033 s32 delta;
0034 ktime_t last;
0035 struct rb_root_cached head;
0036 struct qdisc_watchdog watchdog;
0037 ktime_t (*get_time)(void);
0038 };
0039
0040 static const struct nla_policy etf_policy[TCA_ETF_MAX + 1] = {
0041 [TCA_ETF_PARMS] = { .len = sizeof(struct tc_etf_qopt) },
0042 };
0043
0044 static inline int validate_input_params(struct tc_etf_qopt *qopt,
0045 struct netlink_ext_ack *extack)
0046 {
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057 if (qopt->clockid < 0) {
0058 NL_SET_ERR_MSG(extack, "Dynamic clockids are not supported");
0059 return -ENOTSUPP;
0060 }
0061
0062 if (qopt->clockid != CLOCK_TAI) {
0063 NL_SET_ERR_MSG(extack, "Invalid clockid. CLOCK_TAI must be used");
0064 return -EINVAL;
0065 }
0066
0067 if (qopt->delta < 0) {
0068 NL_SET_ERR_MSG(extack, "Delta must be positive");
0069 return -EINVAL;
0070 }
0071
0072 return 0;
0073 }
0074
0075 static bool is_packet_valid(struct Qdisc *sch, struct sk_buff *nskb)
0076 {
0077 struct etf_sched_data *q = qdisc_priv(sch);
0078 ktime_t txtime = nskb->tstamp;
0079 struct sock *sk = nskb->sk;
0080 ktime_t now;
0081
0082 if (q->skip_sock_check)
0083 goto skip;
0084
0085 if (!sk || !sk_fullsock(sk))
0086 return false;
0087
0088 if (!sock_flag(sk, SOCK_TXTIME))
0089 return false;
0090
0091
0092
0093
0094 if (sk->sk_clockid != q->clockid)
0095 return false;
0096
0097 if (sk->sk_txtime_deadline_mode != q->deadline_mode)
0098 return false;
0099
0100 skip:
0101 now = q->get_time();
0102 if (ktime_before(txtime, now) || ktime_before(txtime, q->last))
0103 return false;
0104
0105 return true;
0106 }
0107
0108 static struct sk_buff *etf_peek_timesortedlist(struct Qdisc *sch)
0109 {
0110 struct etf_sched_data *q = qdisc_priv(sch);
0111 struct rb_node *p;
0112
0113 p = rb_first_cached(&q->head);
0114 if (!p)
0115 return NULL;
0116
0117 return rb_to_skb(p);
0118 }
0119
0120 static void reset_watchdog(struct Qdisc *sch)
0121 {
0122 struct etf_sched_data *q = qdisc_priv(sch);
0123 struct sk_buff *skb = etf_peek_timesortedlist(sch);
0124 ktime_t next;
0125
0126 if (!skb) {
0127 qdisc_watchdog_cancel(&q->watchdog);
0128 return;
0129 }
0130
0131 next = ktime_sub_ns(skb->tstamp, q->delta);
0132 qdisc_watchdog_schedule_ns(&q->watchdog, ktime_to_ns(next));
0133 }
0134
0135 static void report_sock_error(struct sk_buff *skb, u32 err, u8 code)
0136 {
0137 struct sock_exterr_skb *serr;
0138 struct sk_buff *clone;
0139 ktime_t txtime = skb->tstamp;
0140 struct sock *sk = skb->sk;
0141
0142 if (!sk || !sk_fullsock(sk) || !(sk->sk_txtime_report_errors))
0143 return;
0144
0145 clone = skb_clone(skb, GFP_ATOMIC);
0146 if (!clone)
0147 return;
0148
0149 serr = SKB_EXT_ERR(clone);
0150 serr->ee.ee_errno = err;
0151 serr->ee.ee_origin = SO_EE_ORIGIN_TXTIME;
0152 serr->ee.ee_type = 0;
0153 serr->ee.ee_code = code;
0154 serr->ee.ee_pad = 0;
0155 serr->ee.ee_data = (txtime >> 32);
0156 serr->ee.ee_info = txtime;
0157
0158 if (sock_queue_err_skb(sk, clone))
0159 kfree_skb(clone);
0160 }
0161
0162 static int etf_enqueue_timesortedlist(struct sk_buff *nskb, struct Qdisc *sch,
0163 struct sk_buff **to_free)
0164 {
0165 struct etf_sched_data *q = qdisc_priv(sch);
0166 struct rb_node **p = &q->head.rb_root.rb_node, *parent = NULL;
0167 ktime_t txtime = nskb->tstamp;
0168 bool leftmost = true;
0169
0170 if (!is_packet_valid(sch, nskb)) {
0171 report_sock_error(nskb, EINVAL,
0172 SO_EE_CODE_TXTIME_INVALID_PARAM);
0173 return qdisc_drop(nskb, sch, to_free);
0174 }
0175
0176 while (*p) {
0177 struct sk_buff *skb;
0178
0179 parent = *p;
0180 skb = rb_to_skb(parent);
0181 if (ktime_compare(txtime, skb->tstamp) >= 0) {
0182 p = &parent->rb_right;
0183 leftmost = false;
0184 } else {
0185 p = &parent->rb_left;
0186 }
0187 }
0188 rb_link_node(&nskb->rbnode, parent, p);
0189 rb_insert_color_cached(&nskb->rbnode, &q->head, leftmost);
0190
0191 qdisc_qstats_backlog_inc(sch, nskb);
0192 sch->q.qlen++;
0193
0194
0195 reset_watchdog(sch);
0196
0197 return NET_XMIT_SUCCESS;
0198 }
0199
0200 static void timesortedlist_drop(struct Qdisc *sch, struct sk_buff *skb,
0201 ktime_t now)
0202 {
0203 struct etf_sched_data *q = qdisc_priv(sch);
0204 struct sk_buff *to_free = NULL;
0205 struct sk_buff *tmp = NULL;
0206
0207 skb_rbtree_walk_from_safe(skb, tmp) {
0208 if (ktime_after(skb->tstamp, now))
0209 break;
0210
0211 rb_erase_cached(&skb->rbnode, &q->head);
0212
0213
0214
0215
0216 skb->next = NULL;
0217 skb->prev = NULL;
0218 skb->dev = qdisc_dev(sch);
0219
0220 report_sock_error(skb, ECANCELED, SO_EE_CODE_TXTIME_MISSED);
0221
0222 qdisc_qstats_backlog_dec(sch, skb);
0223 qdisc_drop(skb, sch, &to_free);
0224 qdisc_qstats_overlimit(sch);
0225 sch->q.qlen--;
0226 }
0227
0228 kfree_skb_list(to_free);
0229 }
0230
0231 static void timesortedlist_remove(struct Qdisc *sch, struct sk_buff *skb)
0232 {
0233 struct etf_sched_data *q = qdisc_priv(sch);
0234
0235 rb_erase_cached(&skb->rbnode, &q->head);
0236
0237
0238
0239
0240 skb->next = NULL;
0241 skb->prev = NULL;
0242 skb->dev = qdisc_dev(sch);
0243
0244 qdisc_qstats_backlog_dec(sch, skb);
0245
0246 qdisc_bstats_update(sch, skb);
0247
0248 q->last = skb->tstamp;
0249
0250 sch->q.qlen--;
0251 }
0252
0253 static struct sk_buff *etf_dequeue_timesortedlist(struct Qdisc *sch)
0254 {
0255 struct etf_sched_data *q = qdisc_priv(sch);
0256 struct sk_buff *skb;
0257 ktime_t now, next;
0258
0259 skb = etf_peek_timesortedlist(sch);
0260 if (!skb)
0261 return NULL;
0262
0263 now = q->get_time();
0264
0265
0266 if (ktime_before(skb->tstamp, now)) {
0267 timesortedlist_drop(sch, skb, now);
0268 skb = NULL;
0269 goto out;
0270 }
0271
0272
0273
0274
0275 if (q->deadline_mode) {
0276 timesortedlist_remove(sch, skb);
0277 skb->tstamp = now;
0278 goto out;
0279 }
0280
0281 next = ktime_sub_ns(skb->tstamp, q->delta);
0282
0283
0284 if (ktime_after(now, next))
0285 timesortedlist_remove(sch, skb);
0286 else
0287 skb = NULL;
0288
0289 out:
0290
0291 reset_watchdog(sch);
0292
0293 return skb;
0294 }
0295
0296 static void etf_disable_offload(struct net_device *dev,
0297 struct etf_sched_data *q)
0298 {
0299 struct tc_etf_qopt_offload etf = { };
0300 const struct net_device_ops *ops;
0301 int err;
0302
0303 if (!q->offload)
0304 return;
0305
0306 ops = dev->netdev_ops;
0307 if (!ops->ndo_setup_tc)
0308 return;
0309
0310 etf.queue = q->queue;
0311 etf.enable = 0;
0312
0313 err = ops->ndo_setup_tc(dev, TC_SETUP_QDISC_ETF, &etf);
0314 if (err < 0)
0315 pr_warn("Couldn't disable ETF offload for queue %d\n",
0316 etf.queue);
0317 }
0318
0319 static int etf_enable_offload(struct net_device *dev, struct etf_sched_data *q,
0320 struct netlink_ext_ack *extack)
0321 {
0322 const struct net_device_ops *ops = dev->netdev_ops;
0323 struct tc_etf_qopt_offload etf = { };
0324 int err;
0325
0326 if (q->offload)
0327 return 0;
0328
0329 if (!ops->ndo_setup_tc) {
0330 NL_SET_ERR_MSG(extack, "Specified device does not support ETF offload");
0331 return -EOPNOTSUPP;
0332 }
0333
0334 etf.queue = q->queue;
0335 etf.enable = 1;
0336
0337 err = ops->ndo_setup_tc(dev, TC_SETUP_QDISC_ETF, &etf);
0338 if (err < 0) {
0339 NL_SET_ERR_MSG(extack, "Specified device failed to setup ETF hardware offload");
0340 return err;
0341 }
0342
0343 return 0;
0344 }
0345
0346 static int etf_init(struct Qdisc *sch, struct nlattr *opt,
0347 struct netlink_ext_ack *extack)
0348 {
0349 struct etf_sched_data *q = qdisc_priv(sch);
0350 struct net_device *dev = qdisc_dev(sch);
0351 struct nlattr *tb[TCA_ETF_MAX + 1];
0352 struct tc_etf_qopt *qopt;
0353 int err;
0354
0355 if (!opt) {
0356 NL_SET_ERR_MSG(extack,
0357 "Missing ETF qdisc options which are mandatory");
0358 return -EINVAL;
0359 }
0360
0361 err = nla_parse_nested_deprecated(tb, TCA_ETF_MAX, opt, etf_policy,
0362 extack);
0363 if (err < 0)
0364 return err;
0365
0366 if (!tb[TCA_ETF_PARMS]) {
0367 NL_SET_ERR_MSG(extack, "Missing mandatory ETF parameters");
0368 return -EINVAL;
0369 }
0370
0371 qopt = nla_data(tb[TCA_ETF_PARMS]);
0372
0373 pr_debug("delta %d clockid %d offload %s deadline %s\n",
0374 qopt->delta, qopt->clockid,
0375 OFFLOAD_IS_ON(qopt) ? "on" : "off",
0376 DEADLINE_MODE_IS_ON(qopt) ? "on" : "off");
0377
0378 err = validate_input_params(qopt, extack);
0379 if (err < 0)
0380 return err;
0381
0382 q->queue = sch->dev_queue - netdev_get_tx_queue(dev, 0);
0383
0384 if (OFFLOAD_IS_ON(qopt)) {
0385 err = etf_enable_offload(dev, q, extack);
0386 if (err < 0)
0387 return err;
0388 }
0389
0390
0391 q->delta = qopt->delta;
0392 q->clockid = qopt->clockid;
0393 q->offload = OFFLOAD_IS_ON(qopt);
0394 q->deadline_mode = DEADLINE_MODE_IS_ON(qopt);
0395 q->skip_sock_check = SKIP_SOCK_CHECK_IS_SET(qopt);
0396
0397 switch (q->clockid) {
0398 case CLOCK_REALTIME:
0399 q->get_time = ktime_get_real;
0400 break;
0401 case CLOCK_MONOTONIC:
0402 q->get_time = ktime_get;
0403 break;
0404 case CLOCK_BOOTTIME:
0405 q->get_time = ktime_get_boottime;
0406 break;
0407 case CLOCK_TAI:
0408 q->get_time = ktime_get_clocktai;
0409 break;
0410 default:
0411 NL_SET_ERR_MSG(extack, "Clockid is not supported");
0412 return -ENOTSUPP;
0413 }
0414
0415 qdisc_watchdog_init_clockid(&q->watchdog, sch, q->clockid);
0416
0417 return 0;
0418 }
0419
0420 static void timesortedlist_clear(struct Qdisc *sch)
0421 {
0422 struct etf_sched_data *q = qdisc_priv(sch);
0423 struct rb_node *p = rb_first_cached(&q->head);
0424
0425 while (p) {
0426 struct sk_buff *skb = rb_to_skb(p);
0427
0428 p = rb_next(p);
0429
0430 rb_erase_cached(&skb->rbnode, &q->head);
0431 rtnl_kfree_skbs(skb, skb);
0432 sch->q.qlen--;
0433 }
0434 }
0435
0436 static void etf_reset(struct Qdisc *sch)
0437 {
0438 struct etf_sched_data *q = qdisc_priv(sch);
0439
0440
0441 if (q->watchdog.qdisc == sch)
0442 qdisc_watchdog_cancel(&q->watchdog);
0443
0444
0445 timesortedlist_clear(sch);
0446 __qdisc_reset_queue(&sch->q);
0447
0448 sch->qstats.backlog = 0;
0449 sch->q.qlen = 0;
0450
0451 q->last = 0;
0452 }
0453
0454 static void etf_destroy(struct Qdisc *sch)
0455 {
0456 struct etf_sched_data *q = qdisc_priv(sch);
0457 struct net_device *dev = qdisc_dev(sch);
0458
0459
0460 if (q->watchdog.qdisc == sch)
0461 qdisc_watchdog_cancel(&q->watchdog);
0462
0463 etf_disable_offload(dev, q);
0464 }
0465
0466 static int etf_dump(struct Qdisc *sch, struct sk_buff *skb)
0467 {
0468 struct etf_sched_data *q = qdisc_priv(sch);
0469 struct tc_etf_qopt opt = { };
0470 struct nlattr *nest;
0471
0472 nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
0473 if (!nest)
0474 goto nla_put_failure;
0475
0476 opt.delta = q->delta;
0477 opt.clockid = q->clockid;
0478 if (q->offload)
0479 opt.flags |= TC_ETF_OFFLOAD_ON;
0480
0481 if (q->deadline_mode)
0482 opt.flags |= TC_ETF_DEADLINE_MODE_ON;
0483
0484 if (q->skip_sock_check)
0485 opt.flags |= TC_ETF_SKIP_SOCK_CHECK;
0486
0487 if (nla_put(skb, TCA_ETF_PARMS, sizeof(opt), &opt))
0488 goto nla_put_failure;
0489
0490 return nla_nest_end(skb, nest);
0491
0492 nla_put_failure:
0493 nla_nest_cancel(skb, nest);
0494 return -1;
0495 }
0496
0497 static struct Qdisc_ops etf_qdisc_ops __read_mostly = {
0498 .id = "etf",
0499 .priv_size = sizeof(struct etf_sched_data),
0500 .enqueue = etf_enqueue_timesortedlist,
0501 .dequeue = etf_dequeue_timesortedlist,
0502 .peek = etf_peek_timesortedlist,
0503 .init = etf_init,
0504 .reset = etf_reset,
0505 .destroy = etf_destroy,
0506 .dump = etf_dump,
0507 .owner = THIS_MODULE,
0508 };
0509
0510 static int __init etf_module_init(void)
0511 {
0512 return register_qdisc(&etf_qdisc_ops);
0513 }
0514
0515 static void __exit etf_module_exit(void)
0516 {
0517 unregister_qdisc(&etf_qdisc_ops);
0518 }
0519 module_init(etf_module_init)
0520 module_exit(etf_module_exit)
0521 MODULE_LICENSE("GPL");