GNU Linux-libre 4.19.245-gnu1
[releases.git] / net / sched / sch_cbs.c
1 /*
2  * net/sched/sch_cbs.c  Credit Based Shaper
3  *
4  *              This program is free software; you can redistribute it and/or
5  *              modify it under the terms of the GNU General Public License
6  *              as published by the Free Software Foundation; either version
7  *              2 of the License, or (at your option) any later version.
8  *
9  * Authors:     Vinicius Costa Gomes <vinicius.gomes@intel.com>
10  *
11  */
12
13 /* Credit Based Shaper (CBS)
14  * =========================
15  *
16  * This is a simple rate-limiting shaper aimed at TSN applications on
17  * systems with known traffic workloads.
18  *
19  * Its algorithm is defined by the IEEE 802.1Q-2014 Specification,
20  * Section 8.6.8.2, and explained in more detail in the Annex L of the
21  * same specification.
22  *
23  * There are four tunables to be considered:
24  *
25  *      'idleslope': Idleslope is the rate of credits that is
26  *      accumulated (in kilobits per second) when there is at least
27  *      one packet waiting for transmission. Packets are transmitted
28  *      when the current value of credits is equal or greater than
29  *      zero. When there is no packet to be transmitted the amount of
30  *      credits is set to zero. This is the main tunable of the CBS
31  *      algorithm.
32  *
33  *      'sendslope':
34  *      Sendslope is the rate of credits that is depleted (it should be a
35  *      negative number of kilobits per second) when a transmission is
36  *      ocurring. It can be calculated as follows, (IEEE 802.1Q-2014 Section
37  *      8.6.8.2 item g):
38  *
39  *      sendslope = idleslope - port_transmit_rate
40  *
41  *      'hicredit': Hicredit defines the maximum amount of credits (in
42  *      bytes) that can be accumulated. Hicredit depends on the
43  *      characteristics of interfering traffic,
44  *      'max_interference_size' is the maximum size of any burst of
45  *      traffic that can delay the transmission of a frame that is
46  *      available for transmission for this traffic class, (IEEE
47  *      802.1Q-2014 Annex L, Equation L-3):
48  *
49  *      hicredit = max_interference_size * (idleslope / port_transmit_rate)
50  *
51  *      'locredit': Locredit is the minimum amount of credits that can
52  *      be reached. It is a function of the traffic flowing through
53  *      this qdisc (IEEE 802.1Q-2014 Annex L, Equation L-2):
54  *
55  *      locredit = max_frame_size * (sendslope / port_transmit_rate)
56  */
57
58 #include <linux/module.h>
59 #include <linux/types.h>
60 #include <linux/kernel.h>
61 #include <linux/string.h>
62 #include <linux/errno.h>
63 #include <linux/skbuff.h>
64 #include <net/netevent.h>
65 #include <net/netlink.h>
66 #include <net/sch_generic.h>
67 #include <net/pkt_sched.h>
68
69 static LIST_HEAD(cbs_list);
70 static DEFINE_SPINLOCK(cbs_list_lock);
71
72 #define BYTES_PER_KBIT (1000LL / 8)
73
74 struct cbs_sched_data {
75         bool offload;
76         int queue;
77         atomic64_t port_rate; /* in bytes/s */
78         s64 last; /* timestamp in ns */
79         s64 credits; /* in bytes */
80         s32 locredit; /* in bytes */
81         s32 hicredit; /* in bytes */
82         s64 sendslope; /* in bytes/s */
83         s64 idleslope; /* in bytes/s */
84         struct qdisc_watchdog watchdog;
85         int (*enqueue)(struct sk_buff *skb, struct Qdisc *sch,
86                        struct sk_buff **to_free);
87         struct sk_buff *(*dequeue)(struct Qdisc *sch);
88         struct Qdisc *qdisc;
89         struct list_head cbs_list;
90 };
91
92 static int cbs_child_enqueue(struct sk_buff *skb, struct Qdisc *sch,
93                              struct Qdisc *child,
94                              struct sk_buff **to_free)
95 {
96         int err;
97
98         err = child->ops->enqueue(skb, child, to_free);
99         if (err != NET_XMIT_SUCCESS)
100                 return err;
101
102         qdisc_qstats_backlog_inc(sch, skb);
103         sch->q.qlen++;
104
105         return NET_XMIT_SUCCESS;
106 }
107
108 static int cbs_enqueue_offload(struct sk_buff *skb, struct Qdisc *sch,
109                                struct sk_buff **to_free)
110 {
111         struct cbs_sched_data *q = qdisc_priv(sch);
112         struct Qdisc *qdisc = q->qdisc;
113
114         return cbs_child_enqueue(skb, sch, qdisc, to_free);
115 }
116
117 static int cbs_enqueue_soft(struct sk_buff *skb, struct Qdisc *sch,
118                             struct sk_buff **to_free)
119 {
120         struct cbs_sched_data *q = qdisc_priv(sch);
121         struct Qdisc *qdisc = q->qdisc;
122
123         if (sch->q.qlen == 0 && q->credits > 0) {
124                 /* We need to stop accumulating credits when there's
125                  * no enqueued packets and q->credits is positive.
126                  */
127                 q->credits = 0;
128                 q->last = ktime_get_ns();
129         }
130
131         return cbs_child_enqueue(skb, sch, qdisc, to_free);
132 }
133
134 static int cbs_enqueue(struct sk_buff *skb, struct Qdisc *sch,
135                        struct sk_buff **to_free)
136 {
137         struct cbs_sched_data *q = qdisc_priv(sch);
138
139         return q->enqueue(skb, sch, to_free);
140 }
141
142 /* timediff is in ns, slope is in bytes/s */
143 static s64 timediff_to_credits(s64 timediff, s64 slope)
144 {
145         return div64_s64(timediff * slope, NSEC_PER_SEC);
146 }
147
148 static s64 delay_from_credits(s64 credits, s64 slope)
149 {
150         if (unlikely(slope == 0))
151                 return S64_MAX;
152
153         return div64_s64(-credits * NSEC_PER_SEC, slope);
154 }
155
156 static s64 credits_from_len(unsigned int len, s64 slope, s64 port_rate)
157 {
158         if (unlikely(port_rate == 0))
159                 return S64_MAX;
160
161         return div64_s64(len * slope, port_rate);
162 }
163
164 static struct sk_buff *cbs_child_dequeue(struct Qdisc *sch, struct Qdisc *child)
165 {
166         struct sk_buff *skb;
167
168         skb = child->ops->dequeue(child);
169         if (!skb)
170                 return NULL;
171
172         qdisc_qstats_backlog_dec(sch, skb);
173         qdisc_bstats_update(sch, skb);
174         sch->q.qlen--;
175
176         return skb;
177 }
178
179 static struct sk_buff *cbs_dequeue_soft(struct Qdisc *sch)
180 {
181         struct cbs_sched_data *q = qdisc_priv(sch);
182         struct Qdisc *qdisc = q->qdisc;
183         s64 now = ktime_get_ns();
184         struct sk_buff *skb;
185         s64 credits;
186         int len;
187
188         /* The previous packet is still being sent */
189         if (now < q->last) {
190                 qdisc_watchdog_schedule_ns(&q->watchdog, q->last);
191                 return NULL;
192         }
193         if (q->credits < 0) {
194                 credits = timediff_to_credits(now - q->last, q->idleslope);
195
196                 credits = q->credits + credits;
197                 q->credits = min_t(s64, credits, q->hicredit);
198
199                 if (q->credits < 0) {
200                         s64 delay;
201
202                         delay = delay_from_credits(q->credits, q->idleslope);
203                         qdisc_watchdog_schedule_ns(&q->watchdog, now + delay);
204
205                         q->last = now;
206
207                         return NULL;
208                 }
209         }
210         skb = cbs_child_dequeue(sch, qdisc);
211         if (!skb)
212                 return NULL;
213
214         len = qdisc_pkt_len(skb);
215
216         /* As sendslope is a negative number, this will decrease the
217          * amount of q->credits.
218          */
219         credits = credits_from_len(len, q->sendslope,
220                                    atomic64_read(&q->port_rate));
221         credits += q->credits;
222
223         q->credits = max_t(s64, credits, q->locredit);
224         /* Estimate of the transmission of the last byte of the packet in ns */
225         if (unlikely(atomic64_read(&q->port_rate) == 0))
226                 q->last = now;
227         else
228                 q->last = now + div64_s64(len * NSEC_PER_SEC,
229                                           atomic64_read(&q->port_rate));
230
231         return skb;
232 }
233
234 static struct sk_buff *cbs_dequeue_offload(struct Qdisc *sch)
235 {
236         struct cbs_sched_data *q = qdisc_priv(sch);
237         struct Qdisc *qdisc = q->qdisc;
238
239         return cbs_child_dequeue(sch, qdisc);
240 }
241
242 static struct sk_buff *cbs_dequeue(struct Qdisc *sch)
243 {
244         struct cbs_sched_data *q = qdisc_priv(sch);
245
246         return q->dequeue(sch);
247 }
248
249 static const struct nla_policy cbs_policy[TCA_CBS_MAX + 1] = {
250         [TCA_CBS_PARMS] = { .len = sizeof(struct tc_cbs_qopt) },
251 };
252
253 static void cbs_disable_offload(struct net_device *dev,
254                                 struct cbs_sched_data *q)
255 {
256         struct tc_cbs_qopt_offload cbs = { };
257         const struct net_device_ops *ops;
258         int err;
259
260         if (!q->offload)
261                 return;
262
263         q->enqueue = cbs_enqueue_soft;
264         q->dequeue = cbs_dequeue_soft;
265
266         ops = dev->netdev_ops;
267         if (!ops->ndo_setup_tc)
268                 return;
269
270         cbs.queue = q->queue;
271         cbs.enable = 0;
272
273         err = ops->ndo_setup_tc(dev, TC_SETUP_QDISC_CBS, &cbs);
274         if (err < 0)
275                 pr_warn("Couldn't disable CBS offload for queue %d\n",
276                         cbs.queue);
277 }
278
279 static int cbs_enable_offload(struct net_device *dev, struct cbs_sched_data *q,
280                               const struct tc_cbs_qopt *opt,
281                               struct netlink_ext_ack *extack)
282 {
283         const struct net_device_ops *ops = dev->netdev_ops;
284         struct tc_cbs_qopt_offload cbs = { };
285         int err;
286
287         if (!ops->ndo_setup_tc) {
288                 NL_SET_ERR_MSG(extack, "Specified device does not support cbs offload");
289                 return -EOPNOTSUPP;
290         }
291
292         cbs.queue = q->queue;
293
294         cbs.enable = 1;
295         cbs.hicredit = opt->hicredit;
296         cbs.locredit = opt->locredit;
297         cbs.idleslope = opt->idleslope;
298         cbs.sendslope = opt->sendslope;
299
300         err = ops->ndo_setup_tc(dev, TC_SETUP_QDISC_CBS, &cbs);
301         if (err < 0) {
302                 NL_SET_ERR_MSG(extack, "Specified device failed to setup cbs hardware offload");
303                 return err;
304         }
305
306         q->enqueue = cbs_enqueue_offload;
307         q->dequeue = cbs_dequeue_offload;
308
309         return 0;
310 }
311
312 static void cbs_set_port_rate(struct net_device *dev, struct cbs_sched_data *q)
313 {
314         struct ethtool_link_ksettings ecmd;
315         int speed = SPEED_10;
316         int port_rate = -1;
317         int err;
318
319         err = __ethtool_get_link_ksettings(dev, &ecmd);
320         if (err < 0)
321                 goto skip;
322
323         if (ecmd.base.speed && ecmd.base.speed != SPEED_UNKNOWN)
324                 speed = ecmd.base.speed;
325
326 skip:
327         port_rate = speed * 1000 * BYTES_PER_KBIT;
328
329         atomic64_set(&q->port_rate, port_rate);
330         netdev_dbg(dev, "cbs: set %s's port_rate to: %lld, linkspeed: %d\n",
331                    dev->name, (long long)atomic64_read(&q->port_rate),
332                    ecmd.base.speed);
333 }
334
335 static int cbs_dev_notifier(struct notifier_block *nb, unsigned long event,
336                             void *ptr)
337 {
338         struct net_device *dev = netdev_notifier_info_to_dev(ptr);
339         struct cbs_sched_data *q;
340         struct net_device *qdev;
341         bool found = false;
342
343         ASSERT_RTNL();
344
345         if (event != NETDEV_UP && event != NETDEV_CHANGE)
346                 return NOTIFY_DONE;
347
348         spin_lock(&cbs_list_lock);
349         list_for_each_entry(q, &cbs_list, cbs_list) {
350                 qdev = qdisc_dev(q->qdisc);
351                 if (qdev == dev) {
352                         found = true;
353                         break;
354                 }
355         }
356         spin_unlock(&cbs_list_lock);
357
358         if (found)
359                 cbs_set_port_rate(dev, q);
360
361         return NOTIFY_DONE;
362 }
363
364 static int cbs_change(struct Qdisc *sch, struct nlattr *opt,
365                       struct netlink_ext_ack *extack)
366 {
367         struct cbs_sched_data *q = qdisc_priv(sch);
368         struct net_device *dev = qdisc_dev(sch);
369         struct nlattr *tb[TCA_CBS_MAX + 1];
370         struct tc_cbs_qopt *qopt;
371         int err;
372
373         err = nla_parse_nested(tb, TCA_CBS_MAX, opt, cbs_policy, extack);
374         if (err < 0)
375                 return err;
376
377         if (!tb[TCA_CBS_PARMS]) {
378                 NL_SET_ERR_MSG(extack, "Missing CBS parameter which are mandatory");
379                 return -EINVAL;
380         }
381
382         qopt = nla_data(tb[TCA_CBS_PARMS]);
383
384         if (!qopt->offload) {
385                 cbs_set_port_rate(dev, q);
386                 cbs_disable_offload(dev, q);
387         } else {
388                 err = cbs_enable_offload(dev, q, qopt, extack);
389                 if (err < 0)
390                         return err;
391         }
392
393         /* Everything went OK, save the parameters used. */
394         q->hicredit = qopt->hicredit;
395         q->locredit = qopt->locredit;
396         q->idleslope = qopt->idleslope * BYTES_PER_KBIT;
397         q->sendslope = qopt->sendslope * BYTES_PER_KBIT;
398         q->offload = qopt->offload;
399
400         return 0;
401 }
402
403 static int cbs_init(struct Qdisc *sch, struct nlattr *opt,
404                     struct netlink_ext_ack *extack)
405 {
406         struct cbs_sched_data *q = qdisc_priv(sch);
407         struct net_device *dev = qdisc_dev(sch);
408         int err;
409
410         if (!opt) {
411                 NL_SET_ERR_MSG(extack, "Missing CBS qdisc options  which are mandatory");
412                 return -EINVAL;
413         }
414
415         q->qdisc = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
416                                      sch->handle, extack);
417         if (!q->qdisc)
418                 return -ENOMEM;
419
420         qdisc_hash_add(q->qdisc, false);
421
422         q->queue = sch->dev_queue - netdev_get_tx_queue(dev, 0);
423
424         q->enqueue = cbs_enqueue_soft;
425         q->dequeue = cbs_dequeue_soft;
426
427         qdisc_watchdog_init(&q->watchdog, sch);
428
429         err = cbs_change(sch, opt, extack);
430         if (err)
431                 return err;
432
433         if (!q->offload) {
434                 spin_lock(&cbs_list_lock);
435                 list_add(&q->cbs_list, &cbs_list);
436                 spin_unlock(&cbs_list_lock);
437         }
438
439         return 0;
440 }
441
442 static void cbs_destroy(struct Qdisc *sch)
443 {
444         struct cbs_sched_data *q = qdisc_priv(sch);
445         struct net_device *dev = qdisc_dev(sch);
446
447         spin_lock(&cbs_list_lock);
448         list_del(&q->cbs_list);
449         spin_unlock(&cbs_list_lock);
450
451         qdisc_watchdog_cancel(&q->watchdog);
452         cbs_disable_offload(dev, q);
453
454         if (q->qdisc)
455                 qdisc_put(q->qdisc);
456 }
457
458 static int cbs_dump(struct Qdisc *sch, struct sk_buff *skb)
459 {
460         struct cbs_sched_data *q = qdisc_priv(sch);
461         struct tc_cbs_qopt opt = { };
462         struct nlattr *nest;
463
464         nest = nla_nest_start(skb, TCA_OPTIONS);
465         if (!nest)
466                 goto nla_put_failure;
467
468         opt.hicredit = q->hicredit;
469         opt.locredit = q->locredit;
470         opt.sendslope = div64_s64(q->sendslope, BYTES_PER_KBIT);
471         opt.idleslope = div64_s64(q->idleslope, BYTES_PER_KBIT);
472         opt.offload = q->offload;
473
474         if (nla_put(skb, TCA_CBS_PARMS, sizeof(opt), &opt))
475                 goto nla_put_failure;
476
477         return nla_nest_end(skb, nest);
478
479 nla_put_failure:
480         nla_nest_cancel(skb, nest);
481         return -1;
482 }
483
484 static int cbs_dump_class(struct Qdisc *sch, unsigned long cl,
485                           struct sk_buff *skb, struct tcmsg *tcm)
486 {
487         struct cbs_sched_data *q = qdisc_priv(sch);
488
489         if (cl != 1 || !q->qdisc)       /* only one class */
490                 return -ENOENT;
491
492         tcm->tcm_handle |= TC_H_MIN(1);
493         tcm->tcm_info = q->qdisc->handle;
494
495         return 0;
496 }
497
498 static int cbs_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
499                      struct Qdisc **old, struct netlink_ext_ack *extack)
500 {
501         struct cbs_sched_data *q = qdisc_priv(sch);
502
503         if (!new) {
504                 new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
505                                         sch->handle, NULL);
506                 if (!new)
507                         new = &noop_qdisc;
508         }
509
510         *old = qdisc_replace(sch, new, &q->qdisc);
511         return 0;
512 }
513
514 static struct Qdisc *cbs_leaf(struct Qdisc *sch, unsigned long arg)
515 {
516         struct cbs_sched_data *q = qdisc_priv(sch);
517
518         return q->qdisc;
519 }
520
521 static unsigned long cbs_find(struct Qdisc *sch, u32 classid)
522 {
523         return 1;
524 }
525
526 static void cbs_walk(struct Qdisc *sch, struct qdisc_walker *walker)
527 {
528         if (!walker->stop) {
529                 if (walker->count >= walker->skip) {
530                         if (walker->fn(sch, 1, walker) < 0) {
531                                 walker->stop = 1;
532                                 return;
533                         }
534                 }
535                 walker->count++;
536         }
537 }
538
539 static const struct Qdisc_class_ops cbs_class_ops = {
540         .graft          =       cbs_graft,
541         .leaf           =       cbs_leaf,
542         .find           =       cbs_find,
543         .walk           =       cbs_walk,
544         .dump           =       cbs_dump_class,
545 };
546
547 static struct Qdisc_ops cbs_qdisc_ops __read_mostly = {
548         .id             =       "cbs",
549         .cl_ops         =       &cbs_class_ops,
550         .priv_size      =       sizeof(struct cbs_sched_data),
551         .enqueue        =       cbs_enqueue,
552         .dequeue        =       cbs_dequeue,
553         .peek           =       qdisc_peek_dequeued,
554         .init           =       cbs_init,
555         .reset          =       qdisc_reset_queue,
556         .destroy        =       cbs_destroy,
557         .change         =       cbs_change,
558         .dump           =       cbs_dump,
559         .owner          =       THIS_MODULE,
560 };
561
562 static struct notifier_block cbs_device_notifier = {
563         .notifier_call = cbs_dev_notifier,
564 };
565
566 static int __init cbs_module_init(void)
567 {
568         int err;
569
570         err = register_netdevice_notifier(&cbs_device_notifier);
571         if (err)
572                 return err;
573
574         err = register_qdisc(&cbs_qdisc_ops);
575         if (err)
576                 unregister_netdevice_notifier(&cbs_device_notifier);
577
578         return err;
579 }
580
581 static void __exit cbs_module_exit(void)
582 {
583         unregister_qdisc(&cbs_qdisc_ops);
584         unregister_netdevice_notifier(&cbs_device_notifier);
585 }
586 module_init(cbs_module_init)
587 module_exit(cbs_module_exit)
588 MODULE_LICENSE("GPL");