blob: dcef97fa804739df3ae3bc837e1938f3914d6d4f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * net/sched/sch_cbq.c Class-Based Queueing discipline.
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: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10 *
11 */
12
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/module.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090014#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/types.h>
16#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/string.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <linux/errno.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <linux/skbuff.h>
Patrick McHardy0ba48052007-07-02 22:49:07 -070020#include <net/netlink.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <net/pkt_sched.h>
Jiri Pirkocf1facd2017-02-09 14:38:56 +010022#include <net/pkt_cls.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070023
24
25/* Class-Based Queueing (CBQ) algorithm.
26 =======================================
27
28 Sources: [1] Sally Floyd and Van Jacobson, "Link-sharing and Resource
YOSHIFUJI Hideaki10297b92007-02-09 23:25:16 +090029 Management Models for Packet Networks",
Linus Torvalds1da177e2005-04-16 15:20:36 -070030 IEEE/ACM Transactions on Networking, Vol.3, No.4, 1995
31
YOSHIFUJI Hideaki10297b92007-02-09 23:25:16 +090032 [2] Sally Floyd, "Notes on CBQ and Guaranteed Service", 1995
Linus Torvalds1da177e2005-04-16 15:20:36 -070033
YOSHIFUJI Hideaki10297b92007-02-09 23:25:16 +090034 [3] Sally Floyd, "Notes on Class-Based Queueing: Setting
Linus Torvalds1da177e2005-04-16 15:20:36 -070035 Parameters", 1996
36
37 [4] Sally Floyd and Michael Speer, "Experimental Results
38 for Class-Based Queueing", 1998, not published.
39
40 -----------------------------------------------------------------------
41
42 Algorithm skeleton was taken from NS simulator cbq.cc.
43 If someone wants to check this code against the LBL version,
44 he should take into account that ONLY the skeleton was borrowed,
45 the implementation is different. Particularly:
46
47 --- The WRR algorithm is different. Our version looks more
YOSHIFUJI Hideaki10297b92007-02-09 23:25:16 +090048 reasonable (I hope) and works when quanta are allowed to be
49 less than MTU, which is always the case when real time classes
50 have small rates. Note, that the statement of [3] is
51 incomplete, delay may actually be estimated even if class
52 per-round allotment is less than MTU. Namely, if per-round
53 allotment is W*r_i, and r_1+...+r_k = r < 1
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
55 delay_i <= ([MTU/(W*r_i)]*W*r + W*r + k*MTU)/B
56
57 In the worst case we have IntServ estimate with D = W*r+k*MTU
58 and C = MTU*r. The proof (if correct at all) is trivial.
59
60
61 --- It seems that cbq-2.0 is not very accurate. At least, I cannot
62 interpret some places, which look like wrong translations
63 from NS. Anyone is advised to find these differences
64 and explain to me, why I am wrong 8).
65
66 --- Linux has no EOI event, so that we cannot estimate true class
67 idle time. Workaround is to consider the next dequeue event
68 as sign that previous packet is finished. This is wrong because of
69 internal device queueing, but on a permanently loaded link it is true.
70 Moreover, combined with clock integrator, this scheme looks
71 very close to an ideal solution. */
72
73struct cbq_sched_data;
74
75
Eric Dumazetcc7ec452011-01-19 19:26:56 +000076struct cbq_class {
Patrick McHardyd77fea22008-07-05 23:22:05 -070077 struct Qdisc_class_common common;
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 struct cbq_class *next_alive; /* next class with backlog in this priority band */
79
80/* Parameters */
Linus Torvalds1da177e2005-04-16 15:20:36 -070081 unsigned char priority; /* class priority */
82 unsigned char priority2; /* priority to be used after overlimit */
83 unsigned char ewma_log; /* time constant for idle time calculation */
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
85 u32 defmap;
86
87 /* Link-sharing scheduler parameters */
88 long maxidle; /* Class parameters: see below. */
89 long offtime;
90 long minidle;
91 u32 avpkt;
92 struct qdisc_rate_table *R_tab;
93
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 /* General scheduler (WRR) parameters */
95 long allot;
96 long quantum; /* Allotment per WRR round */
97 long weight; /* Relative allotment: see below */
98
99 struct Qdisc *qdisc; /* Ptr to CBQ discipline */
100 struct cbq_class *split; /* Ptr to split node */
101 struct cbq_class *share; /* Ptr to LS parent in the class tree */
102 struct cbq_class *tparent; /* Ptr to tree parent in the class tree */
103 struct cbq_class *borrow; /* NULL if class is bandwidth limited;
104 parent otherwise */
105 struct cbq_class *sibling; /* Sibling chain */
106 struct cbq_class *children; /* Pointer to children chain */
107
108 struct Qdisc *q; /* Elementary queueing discipline */
109
110
111/* Variables */
112 unsigned char cpriority; /* Effective priority */
113 unsigned char delayed;
114 unsigned char level; /* level of the class in hierarchy:
115 0 for leaf classes, and maximal
116 level of children + 1 for nodes.
117 */
118
119 psched_time_t last; /* Last end of service */
120 psched_time_t undertime;
121 long avgidle;
122 long deficit; /* Saved deficit for WRR */
Patrick McHardy1a13cb62007-03-16 01:22:20 -0700123 psched_time_t penalized;
Eric Dumazetc1a8f1f2009-08-16 09:36:49 +0000124 struct gnet_stats_basic_packed bstats;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 struct gnet_stats_queue qstats;
Eric Dumazet1c0d32f2016-12-04 09:48:16 -0800126 struct net_rate_estimator __rcu *rate_est;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 struct tc_cbq_xstats xstats;
128
John Fastabend25d8c0d2014-09-12 20:05:27 -0700129 struct tcf_proto __rcu *filter_list;
Jiri Pirko6529eab2017-05-17 11:07:55 +0200130 struct tcf_block *block;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 int filters;
133
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000134 struct cbq_class *defaults[TC_PRIO_MAX + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135};
136
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000137struct cbq_sched_data {
Patrick McHardyd77fea22008-07-05 23:22:05 -0700138 struct Qdisc_class_hash clhash; /* Hash table of all classes */
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000139 int nclasses[TC_CBQ_MAXPRIO + 1];
140 unsigned int quanta[TC_CBQ_MAXPRIO + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
142 struct cbq_class link;
143
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000144 unsigned int activemask;
145 struct cbq_class *active[TC_CBQ_MAXPRIO + 1]; /* List of all classes
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 with backlog */
147
Patrick McHardyc3bc7cf2007-07-15 00:03:05 -0700148#ifdef CONFIG_NET_CLS_ACT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 struct cbq_class *rx_class;
150#endif
151 struct cbq_class *tx_class;
152 struct cbq_class *tx_borrowed;
153 int tx_len;
154 psched_time_t now; /* Cached timestamp */
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000155 unsigned int pmask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156
David S. Miller2fbd3da2009-09-01 17:59:25 -0700157 struct hrtimer delay_timer;
Patrick McHardy88a99352007-03-16 01:21:11 -0700158 struct qdisc_watchdog watchdog; /* Watchdog timer,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 started when CBQ has
160 backlog, but cannot
161 transmit just now */
Patrick McHardy88a99352007-03-16 01:21:11 -0700162 psched_tdiff_t wd_expires;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 int toplevel;
164 u32 hgenerator;
165};
166
167
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000168#define L2T(cl, len) qdisc_l2t((cl)->R_tab, len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000170static inline struct cbq_class *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171cbq_class_lookup(struct cbq_sched_data *q, u32 classid)
172{
Patrick McHardyd77fea22008-07-05 23:22:05 -0700173 struct Qdisc_class_common *clc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174
Patrick McHardyd77fea22008-07-05 23:22:05 -0700175 clc = qdisc_class_find(&q->clhash, classid);
176 if (clc == NULL)
177 return NULL;
178 return container_of(clc, struct cbq_class, common);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179}
180
Patrick McHardyc3bc7cf2007-07-15 00:03:05 -0700181#ifdef CONFIG_NET_CLS_ACT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
183static struct cbq_class *
184cbq_reclassify(struct sk_buff *skb, struct cbq_class *this)
185{
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000186 struct cbq_class *cl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000188 for (cl = this->tparent; cl; cl = cl->tparent) {
189 struct cbq_class *new = cl->defaults[TC_PRIO_BESTEFFORT];
190
191 if (new != NULL && new != this)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 return new;
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000193 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 return NULL;
195}
196
197#endif
198
199/* Classify packet. The procedure is pretty complicated, but
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000200 * it allows us to combine link sharing and priority scheduling
201 * transparently.
202 *
203 * Namely, you can put link sharing rules (f.e. route based) at root of CBQ,
204 * so that it resolves to split nodes. Then packets are classified
205 * by logical priority, or a more specific classifier may be attached
206 * to the split node.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 */
208
209static struct cbq_class *
210cbq_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
211{
212 struct cbq_sched_data *q = qdisc_priv(sch);
213 struct cbq_class *head = &q->link;
214 struct cbq_class **defmap;
215 struct cbq_class *cl = NULL;
216 u32 prio = skb->priority;
John Fastabend25d8c0d2014-09-12 20:05:27 -0700217 struct tcf_proto *fl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 struct tcf_result res;
219
220 /*
221 * Step 1. If skb->priority points to one of our classes, use it.
222 */
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000223 if (TC_H_MAJ(prio ^ sch->handle) == 0 &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 (cl = cbq_class_lookup(q, prio)) != NULL)
225 return cl;
226
Jarek Poplawskic27f3392008-08-04 22:39:11 -0700227 *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 for (;;) {
229 int result = 0;
230 defmap = head->defaults;
231
John Fastabend25d8c0d2014-09-12 20:05:27 -0700232 fl = rcu_dereference_bh(head->filter_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 /*
234 * Step 2+n. Apply classifier.
235 */
Jiri Pirko87d83092017-05-17 11:07:54 +0200236 result = tcf_classify(skb, fl, &res, true);
John Fastabend25d8c0d2014-09-12 20:05:27 -0700237 if (!fl || result < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 goto fallback;
239
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000240 cl = (void *)res.class;
241 if (!cl) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 if (TC_H_MAJ(res.classid))
243 cl = cbq_class_lookup(q, res.classid);
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000244 else if ((cl = defmap[res.classid & TC_PRIO_MAX]) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 cl = defmap[TC_PRIO_BESTEFFORT];
246
Eric Dumazetbdfc87f2012-09-11 13:11:12 +0000247 if (cl == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 goto fallback;
249 }
Eric Dumazetbdfc87f2012-09-11 13:11:12 +0000250 if (cl->level >= head->level)
251 goto fallback;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252#ifdef CONFIG_NET_CLS_ACT
253 switch (result) {
254 case TC_ACT_QUEUED:
YOSHIFUJI Hideaki10297b92007-02-09 23:25:16 +0900255 case TC_ACT_STOLEN:
Jiri Pirkoe25ea212017-06-06 14:12:02 +0200256 case TC_ACT_TRAP:
Jarek Poplawski378a2f02008-08-04 22:31:03 -0700257 *qerr = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 case TC_ACT_SHOT:
259 return NULL;
Patrick McHardy73ca4912007-07-15 00:02:31 -0700260 case TC_ACT_RECLASSIFY:
261 return cbq_reclassify(skb, cl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263#endif
264 if (cl->level == 0)
265 return cl;
266
267 /*
268 * Step 3+n. If classifier selected a link sharing class,
269 * apply agency specific classifier.
270 * Repeat this procdure until we hit a leaf node.
271 */
272 head = cl;
273 }
274
275fallback:
276 cl = head;
277
278 /*
279 * Step 4. No success...
280 */
281 if (TC_H_MAJ(prio) == 0 &&
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000282 !(cl = head->defaults[prio & TC_PRIO_MAX]) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 !(cl = head->defaults[TC_PRIO_BESTEFFORT]))
284 return head;
285
286 return cl;
287}
288
289/*
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000290 * A packet has just been enqueued on the empty class.
291 * cbq_activate_class adds it to the tail of active class list
292 * of its priority band.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 */
294
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000295static inline void cbq_activate_class(struct cbq_class *cl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296{
297 struct cbq_sched_data *q = qdisc_priv(cl->qdisc);
298 int prio = cl->cpriority;
299 struct cbq_class *cl_tail;
300
301 cl_tail = q->active[prio];
302 q->active[prio] = cl;
303
304 if (cl_tail != NULL) {
305 cl->next_alive = cl_tail->next_alive;
306 cl_tail->next_alive = cl;
307 } else {
308 cl->next_alive = cl;
309 q->activemask |= (1<<prio);
310 }
311}
312
313/*
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000314 * Unlink class from active chain.
315 * Note that this same procedure is done directly in cbq_dequeue*
316 * during round-robin procedure.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 */
318
319static void cbq_deactivate_class(struct cbq_class *this)
320{
321 struct cbq_sched_data *q = qdisc_priv(this->qdisc);
322 int prio = this->cpriority;
323 struct cbq_class *cl;
324 struct cbq_class *cl_prev = q->active[prio];
325
326 do {
327 cl = cl_prev->next_alive;
328 if (cl == this) {
329 cl_prev->next_alive = cl->next_alive;
330 cl->next_alive = NULL;
331
332 if (cl == q->active[prio]) {
333 q->active[prio] = cl_prev;
334 if (cl == q->active[prio]) {
335 q->active[prio] = NULL;
336 q->activemask &= ~(1<<prio);
337 return;
338 }
339 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 return;
341 }
342 } while ((cl_prev = cl) != q->active[prio]);
343}
344
345static void
346cbq_mark_toplevel(struct cbq_sched_data *q, struct cbq_class *cl)
347{
348 int toplevel = q->toplevel;
349
Eric Dumazetcca605d2016-06-10 16:41:37 -0700350 if (toplevel > cl->level) {
Vasily Averin7201c1d2014-08-14 12:27:59 +0400351 psched_time_t now = psched_get_time();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352
353 do {
Patrick McHardy104e0872007-03-23 11:28:07 -0700354 if (cl->undertime < now) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 q->toplevel = cl->level;
356 return;
357 }
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000358 } while ((cl = cl->borrow) != NULL && toplevel > cl->level);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 }
360}
361
362static int
Eric Dumazet520ac302016-06-21 23:16:49 -0700363cbq_enqueue(struct sk_buff *skb, struct Qdisc *sch,
364 struct sk_buff **to_free)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365{
366 struct cbq_sched_data *q = qdisc_priv(sch);
Satyam Sharmaddeee3c2007-09-16 14:54:05 -0700367 int uninitialized_var(ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 struct cbq_class *cl = cbq_classify(skb, sch, &ret);
369
Patrick McHardyc3bc7cf2007-07-15 00:03:05 -0700370#ifdef CONFIG_NET_CLS_ACT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 q->rx_class = cl;
372#endif
373 if (cl == NULL) {
Jarek Poplawskic27f3392008-08-04 22:39:11 -0700374 if (ret & __NET_XMIT_BYPASS)
John Fastabend25331d62014-09-28 11:53:29 -0700375 qdisc_qstats_drop(sch);
Eric Dumazet520ac302016-06-21 23:16:49 -0700376 __qdisc_drop(skb, to_free);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 return ret;
378 }
379
Eric Dumazet520ac302016-06-21 23:16:49 -0700380 ret = qdisc_enqueue(skb, cl->q, to_free);
Jussi Kivilinna5f861732008-07-20 00:08:04 -0700381 if (ret == NET_XMIT_SUCCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 sch->q.qlen++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 cbq_mark_toplevel(q, cl);
384 if (!cl->next_alive)
385 cbq_activate_class(cl);
386 return ret;
387 }
388
Jarek Poplawski378a2f02008-08-04 22:31:03 -0700389 if (net_xmit_drop_count(ret)) {
John Fastabend25331d62014-09-28 11:53:29 -0700390 qdisc_qstats_drop(sch);
Jarek Poplawski378a2f02008-08-04 22:31:03 -0700391 cbq_mark_toplevel(q, cl);
392 cl->qstats.drops++;
393 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 return ret;
395}
396
Florian Westphalc3498d32016-06-09 00:27:39 +0200397/* Overlimit action: penalize leaf class by adding offtime */
398static void cbq_overlimit(struct cbq_class *cl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399{
400 struct cbq_sched_data *q = qdisc_priv(cl->qdisc);
Patrick McHardy8edc0c32007-03-23 11:28:55 -0700401 psched_tdiff_t delay = cl->undertime - q->now;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402
403 if (!cl->delayed) {
404 delay += cl->offtime;
405
YOSHIFUJI Hideaki10297b92007-02-09 23:25:16 +0900406 /*
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000407 * Class goes to sleep, so that it will have no
408 * chance to work avgidle. Let's forgive it 8)
409 *
410 * BTW cbq-2.0 has a crap in this
411 * place, apparently they forgot to shift it by cl->ewma_log.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 */
413 if (cl->avgidle < 0)
414 delay -= (-cl->avgidle) - ((-cl->avgidle) >> cl->ewma_log);
415 if (cl->avgidle < cl->minidle)
416 cl->avgidle = cl->minidle;
417 if (delay <= 0)
418 delay = 1;
Patrick McHardy7c59e252007-03-23 11:27:45 -0700419 cl->undertime = q->now + delay;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420
421 cl->xstats.overactions++;
422 cl->delayed = 1;
423 }
424 if (q->wd_expires == 0 || q->wd_expires > delay)
425 q->wd_expires = delay;
426
427 /* Dirty work! We must schedule wakeups based on
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000428 * real available rate, rather than leaf rate,
429 * which may be tiny (even zero).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 */
431 if (q->toplevel == TC_CBQ_MAXLEVEL) {
432 struct cbq_class *b;
433 psched_tdiff_t base_delay = q->wd_expires;
434
435 for (b = cl->borrow; b; b = b->borrow) {
Patrick McHardy8edc0c32007-03-23 11:28:55 -0700436 delay = b->undertime - q->now;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 if (delay < base_delay) {
438 if (delay <= 0)
439 delay = 1;
440 base_delay = delay;
441 }
442 }
443
444 q->wd_expires = base_delay;
445 }
446}
447
Patrick McHardy1a13cb62007-03-16 01:22:20 -0700448static psched_tdiff_t cbq_undelay_prio(struct cbq_sched_data *q, int prio,
449 psched_time_t now)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450{
451 struct cbq_class *cl;
452 struct cbq_class *cl_prev = q->active[prio];
Patrick McHardy1a13cb62007-03-16 01:22:20 -0700453 psched_time_t sched = now;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454
455 if (cl_prev == NULL)
Patrick McHardye9054a32007-03-16 01:21:40 -0700456 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457
458 do {
459 cl = cl_prev->next_alive;
Patrick McHardy1a13cb62007-03-16 01:22:20 -0700460 if (now - cl->penalized > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 cl_prev->next_alive = cl->next_alive;
462 cl->next_alive = NULL;
463 cl->cpriority = cl->priority;
464 cl->delayed = 0;
465 cbq_activate_class(cl);
466
467 if (cl == q->active[prio]) {
468 q->active[prio] = cl_prev;
469 if (cl == q->active[prio]) {
470 q->active[prio] = NULL;
471 return 0;
472 }
473 }
474
475 cl = cl_prev->next_alive;
Patrick McHardy1a13cb62007-03-16 01:22:20 -0700476 } else if (sched - cl->penalized > 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 sched = cl->penalized;
478 } while ((cl_prev = cl) != q->active[prio]);
479
Patrick McHardy1a13cb62007-03-16 01:22:20 -0700480 return sched - now;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481}
482
Patrick McHardy1a13cb62007-03-16 01:22:20 -0700483static enum hrtimer_restart cbq_undelay(struct hrtimer *timer)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484{
Patrick McHardy1a13cb62007-03-16 01:22:20 -0700485 struct cbq_sched_data *q = container_of(timer, struct cbq_sched_data,
David S. Miller2fbd3da2009-09-01 17:59:25 -0700486 delay_timer);
Patrick McHardy1a13cb62007-03-16 01:22:20 -0700487 struct Qdisc *sch = q->watchdog.qdisc;
488 psched_time_t now;
489 psched_tdiff_t delay = 0;
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000490 unsigned int pmask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491
Patrick McHardy3bebcda2007-03-23 11:29:25 -0700492 now = psched_get_time();
Patrick McHardy1a13cb62007-03-16 01:22:20 -0700493
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 pmask = q->pmask;
495 q->pmask = 0;
496
497 while (pmask) {
498 int prio = ffz(~pmask);
Patrick McHardy1a13cb62007-03-16 01:22:20 -0700499 psched_tdiff_t tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500
501 pmask &= ~(1<<prio);
502
Patrick McHardy1a13cb62007-03-16 01:22:20 -0700503 tmp = cbq_undelay_prio(q, prio, now);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 if (tmp > 0) {
505 q->pmask |= 1<<prio;
506 if (tmp < delay || delay == 0)
507 delay = tmp;
508 }
509 }
510
511 if (delay) {
Patrick McHardy1a13cb62007-03-16 01:22:20 -0700512 ktime_t time;
513
Thomas Gleixner8b0e1952016-12-25 12:30:41 +0100514 time = 0;
Jarek Poplawskica44d6e2009-06-15 02:31:47 -0700515 time = ktime_add_ns(time, PSCHED_TICKS2NS(now + delay));
Eric Dumazet4a8e3202014-09-20 18:01:30 -0700516 hrtimer_start(&q->delay_timer, time, HRTIMER_MODE_ABS_PINNED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 }
518
David S. Miller8608db02008-08-18 20:51:18 -0700519 __netif_schedule(qdisc_root(sch));
Patrick McHardy1a13cb62007-03-16 01:22:20 -0700520 return HRTIMER_NORESTART;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521}
522
YOSHIFUJI Hideaki10297b92007-02-09 23:25:16 +0900523/*
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000524 * It is mission critical procedure.
525 *
526 * We "regenerate" toplevel cutoff, if transmitting class
527 * has backlog and it is not regulated. It is not part of
528 * original CBQ description, but looks more reasonable.
529 * Probably, it is wrong. This question needs further investigation.
530 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000532static inline void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533cbq_update_toplevel(struct cbq_sched_data *q, struct cbq_class *cl,
534 struct cbq_class *borrowed)
535{
536 if (cl && q->toplevel >= borrowed->level) {
537 if (cl->q->q.qlen > 1) {
538 do {
Patrick McHardya0849802007-03-23 11:28:30 -0700539 if (borrowed->undertime == PSCHED_PASTPERFECT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 q->toplevel = borrowed->level;
541 return;
542 }
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000543 } while ((borrowed = borrowed->borrow) != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 }
YOSHIFUJI Hideaki10297b92007-02-09 23:25:16 +0900545#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 /* It is not necessary now. Uncommenting it
547 will save CPU cycles, but decrease fairness.
548 */
549 q->toplevel = TC_CBQ_MAXLEVEL;
550#endif
551 }
552}
553
554static void
555cbq_update(struct cbq_sched_data *q)
556{
557 struct cbq_class *this = q->tx_class;
558 struct cbq_class *cl = this;
559 int len = q->tx_len;
Vasily Averin73d0f372014-08-14 12:27:47 +0400560 psched_time_t now;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561
562 q->tx_class = NULL;
Vasily Averin73d0f372014-08-14 12:27:47 +0400563 /* Time integrator. We calculate EOS time
564 * by adding expected packet transmission time.
565 */
566 now = q->now + L2T(&q->link, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567
568 for ( ; cl; cl = cl->share) {
569 long avgidle = cl->avgidle;
570 long idle;
571
572 cl->bstats.packets++;
573 cl->bstats.bytes += len;
574
575 /*
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000576 * (now - last) is total time between packet right edges.
577 * (last_pktlen/rate) is "virtual" busy time, so that
578 *
579 * idle = (now - last) - last_pktlen/rate
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 */
581
Vasily Averin73d0f372014-08-14 12:27:47 +0400582 idle = now - cl->last;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 if ((unsigned long)idle > 128*1024*1024) {
584 avgidle = cl->maxidle;
585 } else {
586 idle -= L2T(cl, len);
587
588 /* true_avgidle := (1-W)*true_avgidle + W*idle,
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000589 * where W=2^{-ewma_log}. But cl->avgidle is scaled:
590 * cl->avgidle == true_avgidle/W,
591 * hence:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 */
593 avgidle += idle - (avgidle>>cl->ewma_log);
594 }
595
596 if (avgidle <= 0) {
597 /* Overlimit or at-limit */
598
599 if (avgidle < cl->minidle)
600 avgidle = cl->minidle;
601
602 cl->avgidle = avgidle;
603
604 /* Calculate expected time, when this class
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000605 * will be allowed to send.
606 * It will occur, when:
607 * (1-W)*true_avgidle + W*delay = 0, i.e.
608 * idle = (1/W - 1)*(-true_avgidle)
609 * or
610 * idle = (1 - W)*(-cl->avgidle);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 */
612 idle = (-avgidle) - ((-avgidle) >> cl->ewma_log);
613
614 /*
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000615 * That is not all.
616 * To maintain the rate allocated to the class,
617 * we add to undertime virtual clock,
618 * necessary to complete transmitted packet.
619 * (len/phys_bandwidth has been already passed
620 * to the moment of cbq_update)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 */
622
623 idle -= L2T(&q->link, len);
624 idle += L2T(cl, len);
625
Vasily Averin73d0f372014-08-14 12:27:47 +0400626 cl->undertime = now + idle;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 } else {
628 /* Underlimit */
629
Patrick McHardya0849802007-03-23 11:28:30 -0700630 cl->undertime = PSCHED_PASTPERFECT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 if (avgidle > cl->maxidle)
632 cl->avgidle = cl->maxidle;
633 else
634 cl->avgidle = avgidle;
635 }
Vasily Averin73d0f372014-08-14 12:27:47 +0400636 if ((s64)(now - cl->last) > 0)
637 cl->last = now;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 }
639
640 cbq_update_toplevel(q, this, q->tx_borrowed);
641}
642
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000643static inline struct cbq_class *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644cbq_under_limit(struct cbq_class *cl)
645{
646 struct cbq_sched_data *q = qdisc_priv(cl->qdisc);
647 struct cbq_class *this_cl = cl;
648
649 if (cl->tparent == NULL)
650 return cl;
651
Patrick McHardya0849802007-03-23 11:28:30 -0700652 if (cl->undertime == PSCHED_PASTPERFECT || q->now >= cl->undertime) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 cl->delayed = 0;
654 return cl;
655 }
656
657 do {
658 /* It is very suspicious place. Now overlimit
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000659 * action is generated for not bounded classes
660 * only if link is completely congested.
661 * Though it is in agree with ancestor-only paradigm,
662 * it looks very stupid. Particularly,
663 * it means that this chunk of code will either
664 * never be called or result in strong amplification
665 * of burstiness. Dangerous, silly, and, however,
666 * no another solution exists.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 */
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000668 cl = cl->borrow;
669 if (!cl) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 this_cl->qstats.overlimits++;
Florian Westphalc3498d32016-06-09 00:27:39 +0200671 cbq_overlimit(this_cl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 return NULL;
673 }
674 if (cl->level > q->toplevel)
675 return NULL;
Patrick McHardya0849802007-03-23 11:28:30 -0700676 } while (cl->undertime != PSCHED_PASTPERFECT && q->now < cl->undertime);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677
678 cl->delayed = 0;
679 return cl;
680}
681
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000682static inline struct sk_buff *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683cbq_dequeue_prio(struct Qdisc *sch, int prio)
684{
685 struct cbq_sched_data *q = qdisc_priv(sch);
686 struct cbq_class *cl_tail, *cl_prev, *cl;
687 struct sk_buff *skb;
688 int deficit;
689
690 cl_tail = cl_prev = q->active[prio];
691 cl = cl_prev->next_alive;
692
693 do {
694 deficit = 0;
695
696 /* Start round */
697 do {
698 struct cbq_class *borrow = cl;
699
700 if (cl->q->q.qlen &&
701 (borrow = cbq_under_limit(cl)) == NULL)
702 goto skip_class;
703
704 if (cl->deficit <= 0) {
705 /* Class exhausted its allotment per
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000706 * this round. Switch to the next one.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 */
708 deficit = 1;
709 cl->deficit += cl->quantum;
710 goto next_class;
711 }
712
713 skb = cl->q->dequeue(cl->q);
714
715 /* Class did not give us any skb :-(
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000716 * It could occur even if cl->q->q.qlen != 0
717 * f.e. if cl->q == "tbf"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 */
719 if (skb == NULL)
720 goto skip_class;
721
Jussi Kivilinna0abf77e2008-07-20 00:08:27 -0700722 cl->deficit -= qdisc_pkt_len(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 q->tx_class = cl;
724 q->tx_borrowed = borrow;
725 if (borrow != cl) {
726#ifndef CBQ_XSTATS_BORROWS_BYTES
727 borrow->xstats.borrows++;
728 cl->xstats.borrows++;
729#else
Jussi Kivilinna0abf77e2008-07-20 00:08:27 -0700730 borrow->xstats.borrows += qdisc_pkt_len(skb);
731 cl->xstats.borrows += qdisc_pkt_len(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732#endif
733 }
Jussi Kivilinna0abf77e2008-07-20 00:08:27 -0700734 q->tx_len = qdisc_pkt_len(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735
736 if (cl->deficit <= 0) {
737 q->active[prio] = cl;
738 cl = cl->next_alive;
739 cl->deficit += cl->quantum;
740 }
741 return skb;
742
743skip_class:
744 if (cl->q->q.qlen == 0 || prio != cl->cpriority) {
745 /* Class is empty or penalized.
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000746 * Unlink it from active chain.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 */
748 cl_prev->next_alive = cl->next_alive;
749 cl->next_alive = NULL;
750
751 /* Did cl_tail point to it? */
752 if (cl == cl_tail) {
753 /* Repair it! */
754 cl_tail = cl_prev;
755
756 /* Was it the last class in this band? */
757 if (cl == cl_tail) {
758 /* Kill the band! */
759 q->active[prio] = NULL;
760 q->activemask &= ~(1<<prio);
761 if (cl->q->q.qlen)
762 cbq_activate_class(cl);
763 return NULL;
764 }
765
766 q->active[prio] = cl_tail;
767 }
768 if (cl->q->q.qlen)
769 cbq_activate_class(cl);
770
771 cl = cl_prev;
772 }
773
774next_class:
775 cl_prev = cl;
776 cl = cl->next_alive;
777 } while (cl_prev != cl_tail);
778 } while (deficit);
779
780 q->active[prio] = cl_prev;
781
782 return NULL;
783}
784
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000785static inline struct sk_buff *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786cbq_dequeue_1(struct Qdisc *sch)
787{
788 struct cbq_sched_data *q = qdisc_priv(sch);
789 struct sk_buff *skb;
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000790 unsigned int activemask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000792 activemask = q->activemask & 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 while (activemask) {
794 int prio = ffz(~activemask);
795 activemask &= ~(1<<prio);
796 skb = cbq_dequeue_prio(sch, prio);
797 if (skb)
798 return skb;
799 }
800 return NULL;
801}
802
803static struct sk_buff *
804cbq_dequeue(struct Qdisc *sch)
805{
806 struct sk_buff *skb;
807 struct cbq_sched_data *q = qdisc_priv(sch);
808 psched_time_t now;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809
Patrick McHardy3bebcda2007-03-23 11:29:25 -0700810 now = psched_get_time();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
Vasily Averin73d0f372014-08-14 12:27:47 +0400812 if (q->tx_class)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 cbq_update(q);
Vasily Averin73d0f372014-08-14 12:27:47 +0400814
815 q->now = now;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816
817 for (;;) {
818 q->wd_expires = 0;
819
820 skb = cbq_dequeue_1(sch);
821 if (skb) {
Eric Dumazet9190b3b2011-01-20 23:31:33 -0800822 qdisc_bstats_update(sch, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 sch->q.qlen--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 return skb;
825 }
826
827 /* All the classes are overlimit.
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000828 *
829 * It is possible, if:
830 *
831 * 1. Scheduler is empty.
832 * 2. Toplevel cutoff inhibited borrowing.
833 * 3. Root class is overlimit.
834 *
835 * Reset 2d and 3d conditions and retry.
836 *
837 * Note, that NS and cbq-2.0 are buggy, peeking
838 * an arbitrary class is appropriate for ancestor-only
839 * sharing, but not for toplevel algorithm.
840 *
841 * Our version is better, but slower, because it requires
842 * two passes, but it is unavoidable with top-level sharing.
843 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844
845 if (q->toplevel == TC_CBQ_MAXLEVEL &&
Patrick McHardya0849802007-03-23 11:28:30 -0700846 q->link.undertime == PSCHED_PASTPERFECT)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 break;
848
849 q->toplevel = TC_CBQ_MAXLEVEL;
Patrick McHardya0849802007-03-23 11:28:30 -0700850 q->link.undertime = PSCHED_PASTPERFECT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 }
852
853 /* No packets in scheduler or nobody wants to give them to us :-(
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000854 * Sigh... start watchdog timer in the last case.
855 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856
857 if (sch->q.qlen) {
John Fastabend25331d62014-09-28 11:53:29 -0700858 qdisc_qstats_overlimit(sch);
Patrick McHardy88a99352007-03-16 01:21:11 -0700859 if (q->wd_expires)
860 qdisc_watchdog_schedule(&q->watchdog,
Patrick McHardybb239ac2007-03-16 12:31:28 -0700861 now + q->wd_expires);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 }
863 return NULL;
864}
865
866/* CBQ class maintanance routines */
867
868static void cbq_adjust_levels(struct cbq_class *this)
869{
870 if (this == NULL)
871 return;
872
873 do {
874 int level = 0;
875 struct cbq_class *cl;
876
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000877 cl = this->children;
878 if (cl) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 do {
880 if (cl->level > level)
881 level = cl->level;
882 } while ((cl = cl->sibling) != this->children);
883 }
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000884 this->level = level + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 } while ((this = this->tparent) != NULL);
886}
887
888static void cbq_normalize_quanta(struct cbq_sched_data *q, int prio)
889{
890 struct cbq_class *cl;
Patrick McHardyd77fea22008-07-05 23:22:05 -0700891 unsigned int h;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892
893 if (q->quanta[prio] == 0)
894 return;
895
Patrick McHardyd77fea22008-07-05 23:22:05 -0700896 for (h = 0; h < q->clhash.hashsize; h++) {
Sasha Levinb67bfe02013-02-27 17:06:00 -0800897 hlist_for_each_entry(cl, &q->clhash.hash[h], common.hnode) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 /* BUGGGG... Beware! This expression suffer of
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000899 * arithmetic overflows!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 */
901 if (cl->priority == prio) {
902 cl->quantum = (cl->weight*cl->allot*q->nclasses[prio])/
903 q->quanta[prio];
904 }
Yang Yingliang833fa742013-12-10 20:55:32 +0800905 if (cl->quantum <= 0 ||
906 cl->quantum > 32*qdisc_dev(cl->qdisc)->mtu) {
Yang Yingliangc17988a2013-12-23 17:38:58 +0800907 pr_warn("CBQ: class %08x has bad quantum==%ld, repaired.\n",
908 cl->common.classid, cl->quantum);
David S. Miller5ce2d482008-07-08 17:06:30 -0700909 cl->quantum = qdisc_dev(cl->qdisc)->mtu/2 + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 }
911 }
912 }
913}
914
915static void cbq_sync_defmap(struct cbq_class *cl)
916{
917 struct cbq_sched_data *q = qdisc_priv(cl->qdisc);
918 struct cbq_class *split = cl->split;
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000919 unsigned int h;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 int i;
921
922 if (split == NULL)
923 return;
924
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000925 for (i = 0; i <= TC_PRIO_MAX; i++) {
926 if (split->defaults[i] == cl && !(cl->defmap & (1<<i)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 split->defaults[i] = NULL;
928 }
929
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000930 for (i = 0; i <= TC_PRIO_MAX; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 int level = split->level;
932
933 if (split->defaults[i])
934 continue;
935
Patrick McHardyd77fea22008-07-05 23:22:05 -0700936 for (h = 0; h < q->clhash.hashsize; h++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 struct cbq_class *c;
938
Sasha Levinb67bfe02013-02-27 17:06:00 -0800939 hlist_for_each_entry(c, &q->clhash.hash[h],
Patrick McHardyd77fea22008-07-05 23:22:05 -0700940 common.hnode) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 if (c->split == split && c->level < level &&
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000942 c->defmap & (1<<i)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 split->defaults[i] = c;
944 level = c->level;
945 }
946 }
947 }
948 }
949}
950
951static void cbq_change_defmap(struct cbq_class *cl, u32 splitid, u32 def, u32 mask)
952{
953 struct cbq_class *split = NULL;
954
955 if (splitid == 0) {
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000956 split = cl->split;
957 if (!split)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 return;
Patrick McHardyd77fea22008-07-05 23:22:05 -0700959 splitid = split->common.classid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 }
961
Patrick McHardyd77fea22008-07-05 23:22:05 -0700962 if (split == NULL || split->common.classid != splitid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 for (split = cl->tparent; split; split = split->tparent)
Patrick McHardyd77fea22008-07-05 23:22:05 -0700964 if (split->common.classid == splitid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 break;
966 }
967
968 if (split == NULL)
969 return;
970
971 if (cl->split != split) {
972 cl->defmap = 0;
973 cbq_sync_defmap(cl);
974 cl->split = split;
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000975 cl->defmap = def & mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 } else
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000977 cl->defmap = (cl->defmap & ~mask) | (def & mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978
979 cbq_sync_defmap(cl);
980}
981
982static void cbq_unlink_class(struct cbq_class *this)
983{
984 struct cbq_class *cl, **clp;
985 struct cbq_sched_data *q = qdisc_priv(this->qdisc);
986
Patrick McHardyd77fea22008-07-05 23:22:05 -0700987 qdisc_class_hash_remove(&q->clhash, &this->common);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988
989 if (this->tparent) {
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000990 clp = &this->sibling;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 cl = *clp;
992 do {
993 if (cl == this) {
994 *clp = cl->sibling;
995 break;
996 }
997 clp = &cl->sibling;
998 } while ((cl = *clp) != this->sibling);
999
1000 if (this->tparent->children == this) {
1001 this->tparent->children = this->sibling;
1002 if (this->sibling == this)
1003 this->tparent->children = NULL;
1004 }
1005 } else {
Ilpo Järvinen547b7922008-07-25 21:43:18 -07001006 WARN_ON(this->sibling != this);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 }
1008}
1009
1010static void cbq_link_class(struct cbq_class *this)
1011{
1012 struct cbq_sched_data *q = qdisc_priv(this->qdisc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 struct cbq_class *parent = this->tparent;
1014
1015 this->sibling = this;
Patrick McHardyd77fea22008-07-05 23:22:05 -07001016 qdisc_class_hash_insert(&q->clhash, &this->common);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017
1018 if (parent == NULL)
1019 return;
1020
1021 if (parent->children == NULL) {
1022 parent->children = this;
1023 } else {
1024 this->sibling = parent->children->sibling;
1025 parent->children->sibling = this;
1026 }
1027}
1028
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029static void
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001030cbq_reset(struct Qdisc *sch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031{
1032 struct cbq_sched_data *q = qdisc_priv(sch);
1033 struct cbq_class *cl;
1034 int prio;
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001035 unsigned int h;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036
1037 q->activemask = 0;
1038 q->pmask = 0;
1039 q->tx_class = NULL;
1040 q->tx_borrowed = NULL;
Patrick McHardy88a99352007-03-16 01:21:11 -07001041 qdisc_watchdog_cancel(&q->watchdog);
David S. Miller2fbd3da2009-09-01 17:59:25 -07001042 hrtimer_cancel(&q->delay_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 q->toplevel = TC_CBQ_MAXLEVEL;
Patrick McHardy3bebcda2007-03-23 11:29:25 -07001044 q->now = psched_get_time();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045
1046 for (prio = 0; prio <= TC_CBQ_MAXPRIO; prio++)
1047 q->active[prio] = NULL;
1048
Patrick McHardyd77fea22008-07-05 23:22:05 -07001049 for (h = 0; h < q->clhash.hashsize; h++) {
Sasha Levinb67bfe02013-02-27 17:06:00 -08001050 hlist_for_each_entry(cl, &q->clhash.hash[h], common.hnode) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 qdisc_reset(cl->q);
1052
1053 cl->next_alive = NULL;
Patrick McHardya0849802007-03-23 11:28:30 -07001054 cl->undertime = PSCHED_PASTPERFECT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 cl->avgidle = cl->maxidle;
1056 cl->deficit = cl->quantum;
1057 cl->cpriority = cl->priority;
1058 }
1059 }
1060 sch->q.qlen = 0;
1061}
1062
1063
1064static int cbq_set_lss(struct cbq_class *cl, struct tc_cbq_lssopt *lss)
1065{
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001066 if (lss->change & TCF_CBQ_LSS_FLAGS) {
1067 cl->share = (lss->flags & TCF_CBQ_LSS_ISOLATED) ? NULL : cl->tparent;
1068 cl->borrow = (lss->flags & TCF_CBQ_LSS_BOUNDED) ? NULL : cl->tparent;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 }
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001070 if (lss->change & TCF_CBQ_LSS_EWMA)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 cl->ewma_log = lss->ewma_log;
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001072 if (lss->change & TCF_CBQ_LSS_AVPKT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 cl->avpkt = lss->avpkt;
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001074 if (lss->change & TCF_CBQ_LSS_MINIDLE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 cl->minidle = -(long)lss->minidle;
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001076 if (lss->change & TCF_CBQ_LSS_MAXIDLE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 cl->maxidle = lss->maxidle;
1078 cl->avgidle = lss->maxidle;
1079 }
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001080 if (lss->change & TCF_CBQ_LSS_OFFTIME)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 cl->offtime = lss->offtime;
1082 return 0;
1083}
1084
1085static void cbq_rmprio(struct cbq_sched_data *q, struct cbq_class *cl)
1086{
1087 q->nclasses[cl->priority]--;
1088 q->quanta[cl->priority] -= cl->weight;
1089 cbq_normalize_quanta(q, cl->priority);
1090}
1091
1092static void cbq_addprio(struct cbq_sched_data *q, struct cbq_class *cl)
1093{
1094 q->nclasses[cl->priority]++;
1095 q->quanta[cl->priority] += cl->weight;
1096 cbq_normalize_quanta(q, cl->priority);
1097}
1098
1099static int cbq_set_wrr(struct cbq_class *cl, struct tc_cbq_wrropt *wrr)
1100{
1101 struct cbq_sched_data *q = qdisc_priv(cl->qdisc);
1102
1103 if (wrr->allot)
1104 cl->allot = wrr->allot;
1105 if (wrr->weight)
1106 cl->weight = wrr->weight;
1107 if (wrr->priority) {
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001108 cl->priority = wrr->priority - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 cl->cpriority = cl->priority;
1110 if (cl->priority >= cl->priority2)
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001111 cl->priority2 = TC_CBQ_MAXPRIO - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 }
1113
1114 cbq_addprio(q, cl);
1115 return 0;
1116}
1117
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118static int cbq_set_fopt(struct cbq_class *cl, struct tc_cbq_fopt *fopt)
1119{
1120 cbq_change_defmap(cl, fopt->split, fopt->defmap, fopt->defchange);
1121 return 0;
1122}
1123
Patrick McHardy27a34212008-01-23 20:35:39 -08001124static const struct nla_policy cbq_policy[TCA_CBQ_MAX + 1] = {
1125 [TCA_CBQ_LSSOPT] = { .len = sizeof(struct tc_cbq_lssopt) },
1126 [TCA_CBQ_WRROPT] = { .len = sizeof(struct tc_cbq_wrropt) },
1127 [TCA_CBQ_FOPT] = { .len = sizeof(struct tc_cbq_fopt) },
1128 [TCA_CBQ_OVL_STRATEGY] = { .len = sizeof(struct tc_cbq_ovl) },
1129 [TCA_CBQ_RATE] = { .len = sizeof(struct tc_ratespec) },
1130 [TCA_CBQ_RTAB] = { .type = NLA_BINARY, .len = TC_RTAB_SIZE },
1131 [TCA_CBQ_POLICE] = { .len = sizeof(struct tc_cbq_police) },
1132};
1133
Patrick McHardy1e904742008-01-22 22:11:17 -08001134static int cbq_init(struct Qdisc *sch, struct nlattr *opt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135{
1136 struct cbq_sched_data *q = qdisc_priv(sch);
Patrick McHardy1e904742008-01-22 22:11:17 -08001137 struct nlattr *tb[TCA_CBQ_MAX + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 struct tc_ratespec *r;
Patrick McHardycee63722008-01-23 20:33:32 -08001139 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140
Nikolay Aleksandrov3501d052017-08-30 12:49:01 +03001141 qdisc_watchdog_init(&q->watchdog, sch);
1142 hrtimer_init(&q->delay_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED);
1143 q->delay_timer.function = cbq_undelay;
1144
1145 if (!opt)
1146 return -EINVAL;
1147
Johannes Bergfceb6432017-04-12 14:34:07 +02001148 err = nla_parse_nested(tb, TCA_CBQ_MAX, opt, cbq_policy, NULL);
Patrick McHardycee63722008-01-23 20:33:32 -08001149 if (err < 0)
1150 return err;
1151
Patrick McHardy27a34212008-01-23 20:35:39 -08001152 if (tb[TCA_CBQ_RTAB] == NULL || tb[TCA_CBQ_RATE] == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 return -EINVAL;
1154
Patrick McHardy1e904742008-01-22 22:11:17 -08001155 r = nla_data(tb[TCA_CBQ_RATE]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156
Patrick McHardy1e904742008-01-22 22:11:17 -08001157 if ((q->link.R_tab = qdisc_get_rtab(r, tb[TCA_CBQ_RTAB])) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 return -EINVAL;
1159
Patrick McHardyd77fea22008-07-05 23:22:05 -07001160 err = qdisc_class_hash_init(&q->clhash);
1161 if (err < 0)
1162 goto put_rtab;
1163
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 q->link.sibling = &q->link;
Patrick McHardyd77fea22008-07-05 23:22:05 -07001165 q->link.common.classid = sch->handle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 q->link.qdisc = sch;
Changli Gao3511c912010-10-16 13:04:08 +00001167 q->link.q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
1168 sch->handle);
1169 if (!q->link.q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 q->link.q = &noop_qdisc;
Jiri Kosina49b49972017-03-08 16:03:32 +01001171 else
1172 qdisc_hash_add(q->link.q, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001174 q->link.priority = TC_CBQ_MAXPRIO - 1;
1175 q->link.priority2 = TC_CBQ_MAXPRIO - 1;
1176 q->link.cpriority = TC_CBQ_MAXPRIO - 1;
David S. Miller5ce2d482008-07-08 17:06:30 -07001177 q->link.allot = psched_mtu(qdisc_dev(sch));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 q->link.quantum = q->link.allot;
1179 q->link.weight = q->link.R_tab->rate.rate;
1180
1181 q->link.ewma_log = TC_CBQ_DEF_EWMA;
1182 q->link.avpkt = q->link.allot/2;
1183 q->link.minidle = -0x7FFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 q->toplevel = TC_CBQ_MAXLEVEL;
Patrick McHardy3bebcda2007-03-23 11:29:25 -07001186 q->now = psched_get_time();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187
1188 cbq_link_class(&q->link);
1189
Patrick McHardy1e904742008-01-22 22:11:17 -08001190 if (tb[TCA_CBQ_LSSOPT])
1191 cbq_set_lss(&q->link, nla_data(tb[TCA_CBQ_LSSOPT]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192
1193 cbq_addprio(q, &q->link);
1194 return 0;
Patrick McHardyd77fea22008-07-05 23:22:05 -07001195
1196put_rtab:
1197 qdisc_put_rtab(q->link.R_tab);
1198 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199}
1200
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001201static int cbq_dump_rate(struct sk_buff *skb, struct cbq_class *cl)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202{
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07001203 unsigned char *b = skb_tail_pointer(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204
David S. Miller1b34ec42012-03-29 05:11:39 -04001205 if (nla_put(skb, TCA_CBQ_RATE, sizeof(cl->R_tab->rate), &cl->R_tab->rate))
1206 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 return skb->len;
1208
Patrick McHardy1e904742008-01-22 22:11:17 -08001209nla_put_failure:
Arnaldo Carvalho de Melodc5fc572007-03-25 23:06:12 -07001210 nlmsg_trim(skb, b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 return -1;
1212}
1213
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001214static int cbq_dump_lss(struct sk_buff *skb, struct cbq_class *cl)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215{
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07001216 unsigned char *b = skb_tail_pointer(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 struct tc_cbq_lssopt opt;
1218
1219 opt.flags = 0;
1220 if (cl->borrow == NULL)
1221 opt.flags |= TCF_CBQ_LSS_BOUNDED;
1222 if (cl->share == NULL)
1223 opt.flags |= TCF_CBQ_LSS_ISOLATED;
1224 opt.ewma_log = cl->ewma_log;
1225 opt.level = cl->level;
1226 opt.avpkt = cl->avpkt;
1227 opt.maxidle = cl->maxidle;
1228 opt.minidle = (u32)(-cl->minidle);
1229 opt.offtime = cl->offtime;
1230 opt.change = ~0;
David S. Miller1b34ec42012-03-29 05:11:39 -04001231 if (nla_put(skb, TCA_CBQ_LSSOPT, sizeof(opt), &opt))
1232 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 return skb->len;
1234
Patrick McHardy1e904742008-01-22 22:11:17 -08001235nla_put_failure:
Arnaldo Carvalho de Melodc5fc572007-03-25 23:06:12 -07001236 nlmsg_trim(skb, b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 return -1;
1238}
1239
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001240static int cbq_dump_wrr(struct sk_buff *skb, struct cbq_class *cl)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241{
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07001242 unsigned char *b = skb_tail_pointer(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 struct tc_cbq_wrropt opt;
1244
David S. Millera0db8562013-07-30 00:16:21 -07001245 memset(&opt, 0, sizeof(opt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 opt.flags = 0;
1247 opt.allot = cl->allot;
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001248 opt.priority = cl->priority + 1;
1249 opt.cpriority = cl->cpriority + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 opt.weight = cl->weight;
David S. Miller1b34ec42012-03-29 05:11:39 -04001251 if (nla_put(skb, TCA_CBQ_WRROPT, sizeof(opt), &opt))
1252 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 return skb->len;
1254
Patrick McHardy1e904742008-01-22 22:11:17 -08001255nla_put_failure:
Arnaldo Carvalho de Melodc5fc572007-03-25 23:06:12 -07001256 nlmsg_trim(skb, b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 return -1;
1258}
1259
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001260static int cbq_dump_fopt(struct sk_buff *skb, struct cbq_class *cl)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261{
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07001262 unsigned char *b = skb_tail_pointer(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 struct tc_cbq_fopt opt;
1264
1265 if (cl->split || cl->defmap) {
Patrick McHardyd77fea22008-07-05 23:22:05 -07001266 opt.split = cl->split ? cl->split->common.classid : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 opt.defmap = cl->defmap;
1268 opt.defchange = ~0;
David S. Miller1b34ec42012-03-29 05:11:39 -04001269 if (nla_put(skb, TCA_CBQ_FOPT, sizeof(opt), &opt))
1270 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 }
1272 return skb->len;
1273
Patrick McHardy1e904742008-01-22 22:11:17 -08001274nla_put_failure:
Arnaldo Carvalho de Melodc5fc572007-03-25 23:06:12 -07001275 nlmsg_trim(skb, b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 return -1;
1277}
1278
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279static int cbq_dump_attr(struct sk_buff *skb, struct cbq_class *cl)
1280{
1281 if (cbq_dump_lss(skb, cl) < 0 ||
1282 cbq_dump_rate(skb, cl) < 0 ||
1283 cbq_dump_wrr(skb, cl) < 0 ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 cbq_dump_fopt(skb, cl) < 0)
1285 return -1;
1286 return 0;
1287}
1288
1289static int cbq_dump(struct Qdisc *sch, struct sk_buff *skb)
1290{
1291 struct cbq_sched_data *q = qdisc_priv(sch);
Patrick McHardy4b3550ef2008-01-23 20:34:11 -08001292 struct nlattr *nest;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293
Patrick McHardy4b3550ef2008-01-23 20:34:11 -08001294 nest = nla_nest_start(skb, TCA_OPTIONS);
1295 if (nest == NULL)
1296 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 if (cbq_dump_attr(skb, &q->link) < 0)
Patrick McHardy1e904742008-01-22 22:11:17 -08001298 goto nla_put_failure;
Yang Yingliangd59b7d82014-03-12 10:20:32 +08001299 return nla_nest_end(skb, nest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300
Patrick McHardy1e904742008-01-22 22:11:17 -08001301nla_put_failure:
Patrick McHardy4b3550ef2008-01-23 20:34:11 -08001302 nla_nest_cancel(skb, nest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 return -1;
1304}
1305
1306static int
1307cbq_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
1308{
1309 struct cbq_sched_data *q = qdisc_priv(sch);
1310
1311 q->link.xstats.avgidle = q->link.avgidle;
1312 return gnet_stats_copy_app(d, &q->link.xstats, sizeof(q->link.xstats));
1313}
1314
1315static int
1316cbq_dump_class(struct Qdisc *sch, unsigned long arg,
1317 struct sk_buff *skb, struct tcmsg *tcm)
1318{
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001319 struct cbq_class *cl = (struct cbq_class *)arg;
Patrick McHardy4b3550ef2008-01-23 20:34:11 -08001320 struct nlattr *nest;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321
1322 if (cl->tparent)
Patrick McHardyd77fea22008-07-05 23:22:05 -07001323 tcm->tcm_parent = cl->tparent->common.classid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 else
1325 tcm->tcm_parent = TC_H_ROOT;
Patrick McHardyd77fea22008-07-05 23:22:05 -07001326 tcm->tcm_handle = cl->common.classid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 tcm->tcm_info = cl->q->handle;
1328
Patrick McHardy4b3550ef2008-01-23 20:34:11 -08001329 nest = nla_nest_start(skb, TCA_OPTIONS);
1330 if (nest == NULL)
1331 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 if (cbq_dump_attr(skb, cl) < 0)
Patrick McHardy1e904742008-01-22 22:11:17 -08001333 goto nla_put_failure;
Yang Yingliangd59b7d82014-03-12 10:20:32 +08001334 return nla_nest_end(skb, nest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335
Patrick McHardy1e904742008-01-22 22:11:17 -08001336nla_put_failure:
Patrick McHardy4b3550ef2008-01-23 20:34:11 -08001337 nla_nest_cancel(skb, nest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 return -1;
1339}
1340
1341static int
1342cbq_dump_class_stats(struct Qdisc *sch, unsigned long arg,
1343 struct gnet_dump *d)
1344{
1345 struct cbq_sched_data *q = qdisc_priv(sch);
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001346 struct cbq_class *cl = (struct cbq_class *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 cl->xstats.avgidle = cl->avgidle;
1349 cl->xstats.undertime = 0;
1350
Patrick McHardya0849802007-03-23 11:28:30 -07001351 if (cl->undertime != PSCHED_PASTPERFECT)
Patrick McHardy8edc0c32007-03-23 11:28:55 -07001352 cl->xstats.undertime = cl->undertime - q->now;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353
Eric Dumazetedb09eb2016-06-06 09:37:16 -07001354 if (gnet_stats_copy_basic(qdisc_root_sleeping_running(sch),
1355 d, NULL, &cl->bstats) < 0 ||
Eric Dumazet1c0d32f2016-12-04 09:48:16 -08001356 gnet_stats_copy_rate_est(d, &cl->rate_est) < 0 ||
John Fastabendb0ab6f92014-09-28 11:54:24 -07001357 gnet_stats_copy_queue(d, NULL, &cl->qstats, cl->q->q.qlen) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 return -1;
1359
1360 return gnet_stats_copy_app(d, &cl->xstats, sizeof(cl->xstats));
1361}
1362
1363static int cbq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
1364 struct Qdisc **old)
1365{
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001366 struct cbq_class *cl = (struct cbq_class *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367
Patrick McHardy5b9a9cc2009-09-04 06:41:17 +00001368 if (new == NULL) {
Changli Gao3511c912010-10-16 13:04:08 +00001369 new = qdisc_create_dflt(sch->dev_queue,
Patrick McHardy5b9a9cc2009-09-04 06:41:17 +00001370 &pfifo_qdisc_ops, cl->common.classid);
1371 if (new == NULL)
1372 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 }
Patrick McHardy5b9a9cc2009-09-04 06:41:17 +00001374
WANG Cong86a79962016-02-25 14:55:00 -08001375 *old = qdisc_replace(sch, new, &cl->q);
Patrick McHardy5b9a9cc2009-09-04 06:41:17 +00001376 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377}
1378
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001379static struct Qdisc *cbq_leaf(struct Qdisc *sch, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380{
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001381 struct cbq_class *cl = (struct cbq_class *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382
Patrick McHardy5b9a9cc2009-09-04 06:41:17 +00001383 return cl->q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384}
1385
Jarek Poplawskia37ef2e2006-12-08 00:25:55 -08001386static void cbq_qlen_notify(struct Qdisc *sch, unsigned long arg)
1387{
1388 struct cbq_class *cl = (struct cbq_class *)arg;
1389
Konstantin Khlebnikov95946652017-08-15 16:39:59 +03001390 cbq_deactivate_class(cl);
Jarek Poplawskia37ef2e2006-12-08 00:25:55 -08001391}
1392
WANG Cong143976c2017-08-24 16:51:29 -07001393static unsigned long cbq_find(struct Qdisc *sch, u32 classid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394{
1395 struct cbq_sched_data *q = qdisc_priv(sch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396
WANG Cong143976c2017-08-24 16:51:29 -07001397 return (unsigned long)cbq_class_lookup(q, classid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398}
1399
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400static void cbq_destroy_class(struct Qdisc *sch, struct cbq_class *cl)
1401{
1402 struct cbq_sched_data *q = qdisc_priv(sch);
1403
Ilpo Järvinen547b7922008-07-25 21:43:18 -07001404 WARN_ON(cl->filters);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405
Jiri Pirko6529eab2017-05-17 11:07:55 +02001406 tcf_block_put(cl->block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 qdisc_destroy(cl->q);
1408 qdisc_put_rtab(cl->R_tab);
Eric Dumazet1c0d32f2016-12-04 09:48:16 -08001409 gen_kill_estimator(&cl->rate_est);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 if (cl != &q->link)
1411 kfree(cl);
1412}
1413
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001414static void cbq_destroy(struct Qdisc *sch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415{
1416 struct cbq_sched_data *q = qdisc_priv(sch);
Sasha Levinb67bfe02013-02-27 17:06:00 -08001417 struct hlist_node *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 struct cbq_class *cl;
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001419 unsigned int h;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420
Patrick McHardyc3bc7cf2007-07-15 00:03:05 -07001421#ifdef CONFIG_NET_CLS_ACT
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 q->rx_class = NULL;
1423#endif
1424 /*
1425 * Filters must be destroyed first because we don't destroy the
1426 * classes from root to leafs which means that filters can still
1427 * be bound to classes which have been destroyed already. --TGR '04
1428 */
Patrick McHardyd77fea22008-07-05 23:22:05 -07001429 for (h = 0; h < q->clhash.hashsize; h++) {
Konstantin Khlebnikov89890422017-08-15 16:35:21 +03001430 hlist_for_each_entry(cl, &q->clhash.hash[h], common.hnode) {
Jiri Pirko6529eab2017-05-17 11:07:55 +02001431 tcf_block_put(cl->block);
Konstantin Khlebnikov89890422017-08-15 16:35:21 +03001432 cl->block = NULL;
1433 }
Patrick McHardyb00b4bf2007-06-05 16:06:59 -07001434 }
Patrick McHardyd77fea22008-07-05 23:22:05 -07001435 for (h = 0; h < q->clhash.hashsize; h++) {
Sasha Levinb67bfe02013-02-27 17:06:00 -08001436 hlist_for_each_entry_safe(cl, next, &q->clhash.hash[h],
Patrick McHardyd77fea22008-07-05 23:22:05 -07001437 common.hnode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 cbq_destroy_class(sch, cl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 }
Patrick McHardyd77fea22008-07-05 23:22:05 -07001440 qdisc_class_hash_destroy(&q->clhash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441}
1442
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443static int
Patrick McHardy1e904742008-01-22 22:11:17 -08001444cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **tca,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445 unsigned long *arg)
1446{
1447 int err;
1448 struct cbq_sched_data *q = qdisc_priv(sch);
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001449 struct cbq_class *cl = (struct cbq_class *)*arg;
Patrick McHardy1e904742008-01-22 22:11:17 -08001450 struct nlattr *opt = tca[TCA_OPTIONS];
1451 struct nlattr *tb[TCA_CBQ_MAX + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 struct cbq_class *parent;
1453 struct qdisc_rate_table *rtab = NULL;
1454
Patrick McHardycee63722008-01-23 20:33:32 -08001455 if (opt == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 return -EINVAL;
1457
Johannes Bergfceb6432017-04-12 14:34:07 +02001458 err = nla_parse_nested(tb, TCA_CBQ_MAX, opt, cbq_policy, NULL);
Patrick McHardycee63722008-01-23 20:33:32 -08001459 if (err < 0)
1460 return err;
1461
Florian Westphaldd47c1f2016-06-09 00:27:40 +02001462 if (tb[TCA_CBQ_OVL_STRATEGY] || tb[TCA_CBQ_POLICE])
Florian Westphalc3498d32016-06-09 00:27:39 +02001463 return -EOPNOTSUPP;
1464
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 if (cl) {
1466 /* Check parent */
1467 if (parentid) {
Patrick McHardyd77fea22008-07-05 23:22:05 -07001468 if (cl->tparent &&
1469 cl->tparent->common.classid != parentid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 return -EINVAL;
1471 if (!cl->tparent && parentid != TC_H_ROOT)
1472 return -EINVAL;
1473 }
1474
Patrick McHardy1e904742008-01-22 22:11:17 -08001475 if (tb[TCA_CBQ_RATE]) {
Stephen Hemminger71bcb092008-11-25 21:13:31 -08001476 rtab = qdisc_get_rtab(nla_data(tb[TCA_CBQ_RATE]),
1477 tb[TCA_CBQ_RTAB]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 if (rtab == NULL)
1479 return -EINVAL;
1480 }
1481
Stephen Hemminger71bcb092008-11-25 21:13:31 -08001482 if (tca[TCA_RATE]) {
John Fastabend22e0f8b2014-09-28 11:52:56 -07001483 err = gen_replace_estimator(&cl->bstats, NULL,
1484 &cl->rate_est,
Eric Dumazetedb09eb2016-06-06 09:37:16 -07001485 NULL,
1486 qdisc_root_sleeping_running(sch),
Stephen Hemminger71bcb092008-11-25 21:13:31 -08001487 tca[TCA_RATE]);
1488 if (err) {
Yang Yingliang79c11f22013-12-17 15:29:17 +08001489 qdisc_put_rtab(rtab);
Stephen Hemminger71bcb092008-11-25 21:13:31 -08001490 return err;
1491 }
1492 }
1493
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 /* Change class parameters */
1495 sch_tree_lock(sch);
1496
1497 if (cl->next_alive != NULL)
1498 cbq_deactivate_class(cl);
1499
1500 if (rtab) {
Patrick McHardyb94c8af2008-11-20 04:11:36 -08001501 qdisc_put_rtab(cl->R_tab);
1502 cl->R_tab = rtab;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 }
1504
Patrick McHardy1e904742008-01-22 22:11:17 -08001505 if (tb[TCA_CBQ_LSSOPT])
1506 cbq_set_lss(cl, nla_data(tb[TCA_CBQ_LSSOPT]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507
Patrick McHardy1e904742008-01-22 22:11:17 -08001508 if (tb[TCA_CBQ_WRROPT]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 cbq_rmprio(q, cl);
Patrick McHardy1e904742008-01-22 22:11:17 -08001510 cbq_set_wrr(cl, nla_data(tb[TCA_CBQ_WRROPT]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 }
1512
Patrick McHardy1e904742008-01-22 22:11:17 -08001513 if (tb[TCA_CBQ_FOPT])
1514 cbq_set_fopt(cl, nla_data(tb[TCA_CBQ_FOPT]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515
1516 if (cl->q->q.qlen)
1517 cbq_activate_class(cl);
1518
1519 sch_tree_unlock(sch);
1520
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 return 0;
1522 }
1523
1524 if (parentid == TC_H_ROOT)
1525 return -EINVAL;
1526
Patrick McHardy1e904742008-01-22 22:11:17 -08001527 if (tb[TCA_CBQ_WRROPT] == NULL || tb[TCA_CBQ_RATE] == NULL ||
1528 tb[TCA_CBQ_LSSOPT] == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 return -EINVAL;
1530
Patrick McHardy1e904742008-01-22 22:11:17 -08001531 rtab = qdisc_get_rtab(nla_data(tb[TCA_CBQ_RATE]), tb[TCA_CBQ_RTAB]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 if (rtab == NULL)
1533 return -EINVAL;
1534
1535 if (classid) {
1536 err = -EINVAL;
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001537 if (TC_H_MAJ(classid ^ sch->handle) ||
1538 cbq_class_lookup(q, classid))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 goto failure;
1540 } else {
1541 int i;
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001542 classid = TC_H_MAKE(sch->handle, 0x8000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001544 for (i = 0; i < 0x8000; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 if (++q->hgenerator >= 0x8000)
1546 q->hgenerator = 1;
1547 if (cbq_class_lookup(q, classid|q->hgenerator) == NULL)
1548 break;
1549 }
1550 err = -ENOSR;
1551 if (i >= 0x8000)
1552 goto failure;
1553 classid = classid|q->hgenerator;
1554 }
1555
1556 parent = &q->link;
1557 if (parentid) {
1558 parent = cbq_class_lookup(q, parentid);
1559 err = -EINVAL;
1560 if (parent == NULL)
1561 goto failure;
1562 }
1563
1564 err = -ENOBUFS;
Panagiotis Issaris0da974f2006-07-21 14:51:30 -07001565 cl = kzalloc(sizeof(*cl), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 if (cl == NULL)
1567 goto failure;
Stephen Hemminger71bcb092008-11-25 21:13:31 -08001568
Jiri Pirko6529eab2017-05-17 11:07:55 +02001569 err = tcf_block_get(&cl->block, &cl->filter_list);
1570 if (err) {
1571 kfree(cl);
1572 return err;
1573 }
1574
Stephen Hemminger71bcb092008-11-25 21:13:31 -08001575 if (tca[TCA_RATE]) {
John Fastabend22e0f8b2014-09-28 11:52:56 -07001576 err = gen_new_estimator(&cl->bstats, NULL, &cl->rate_est,
Eric Dumazetedb09eb2016-06-06 09:37:16 -07001577 NULL,
1578 qdisc_root_sleeping_running(sch),
Stephen Hemminger71bcb092008-11-25 21:13:31 -08001579 tca[TCA_RATE]);
1580 if (err) {
Jiri Pirko6529eab2017-05-17 11:07:55 +02001581 tcf_block_put(cl->block);
Stephen Hemminger71bcb092008-11-25 21:13:31 -08001582 kfree(cl);
1583 goto failure;
1584 }
1585 }
1586
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 cl->R_tab = rtab;
1588 rtab = NULL;
Changli Gao3511c912010-10-16 13:04:08 +00001589 cl->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, classid);
1590 if (!cl->q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 cl->q = &noop_qdisc;
Jiri Kosina49b49972017-03-08 16:03:32 +01001592 else
1593 qdisc_hash_add(cl->q, true);
1594
Patrick McHardyd77fea22008-07-05 23:22:05 -07001595 cl->common.classid = classid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 cl->tparent = parent;
1597 cl->qdisc = sch;
1598 cl->allot = parent->allot;
1599 cl->quantum = cl->allot;
1600 cl->weight = cl->R_tab->rate.rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601
1602 sch_tree_lock(sch);
1603 cbq_link_class(cl);
1604 cl->borrow = cl->tparent;
1605 if (cl->tparent != &q->link)
1606 cl->share = cl->tparent;
1607 cbq_adjust_levels(parent);
1608 cl->minidle = -0x7FFFFFFF;
Patrick McHardy1e904742008-01-22 22:11:17 -08001609 cbq_set_lss(cl, nla_data(tb[TCA_CBQ_LSSOPT]));
1610 cbq_set_wrr(cl, nla_data(tb[TCA_CBQ_WRROPT]));
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001611 if (cl->ewma_log == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 cl->ewma_log = q->link.ewma_log;
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001613 if (cl->maxidle == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 cl->maxidle = q->link.maxidle;
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001615 if (cl->avpkt == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 cl->avpkt = q->link.avpkt;
Patrick McHardy1e904742008-01-22 22:11:17 -08001617 if (tb[TCA_CBQ_FOPT])
1618 cbq_set_fopt(cl, nla_data(tb[TCA_CBQ_FOPT]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 sch_tree_unlock(sch);
1620
Patrick McHardyd77fea22008-07-05 23:22:05 -07001621 qdisc_class_hash_grow(sch, &q->clhash);
1622
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 *arg = (unsigned long)cl;
1624 return 0;
1625
1626failure:
1627 qdisc_put_rtab(rtab);
1628 return err;
1629}
1630
1631static int cbq_delete(struct Qdisc *sch, unsigned long arg)
1632{
1633 struct cbq_sched_data *q = qdisc_priv(sch);
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001634 struct cbq_class *cl = (struct cbq_class *)arg;
WANG Cong2ccccf52016-02-25 14:55:01 -08001635 unsigned int qlen, backlog;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636
1637 if (cl->filters || cl->children || cl == &q->link)
1638 return -EBUSY;
1639
1640 sch_tree_lock(sch);
1641
Jarek Poplawskia37ef2e2006-12-08 00:25:55 -08001642 qlen = cl->q->q.qlen;
WANG Cong2ccccf52016-02-25 14:55:01 -08001643 backlog = cl->q->qstats.backlog;
Jarek Poplawskia37ef2e2006-12-08 00:25:55 -08001644 qdisc_reset(cl->q);
WANG Cong2ccccf52016-02-25 14:55:01 -08001645 qdisc_tree_reduce_backlog(cl->q, qlen, backlog);
Jarek Poplawskia37ef2e2006-12-08 00:25:55 -08001646
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 if (cl->next_alive)
1648 cbq_deactivate_class(cl);
1649
1650 if (q->tx_borrowed == cl)
1651 q->tx_borrowed = q->tx_class;
1652 if (q->tx_class == cl) {
1653 q->tx_class = NULL;
1654 q->tx_borrowed = NULL;
1655 }
Patrick McHardyc3bc7cf2007-07-15 00:03:05 -07001656#ifdef CONFIG_NET_CLS_ACT
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 if (q->rx_class == cl)
1658 q->rx_class = NULL;
1659#endif
1660
1661 cbq_unlink_class(cl);
1662 cbq_adjust_levels(cl->tparent);
1663 cl->defmap = 0;
1664 cbq_sync_defmap(cl);
1665
1666 cbq_rmprio(q, cl);
1667 sch_tree_unlock(sch);
1668
WANG Cong143976c2017-08-24 16:51:29 -07001669 cbq_destroy_class(sch, cl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 return 0;
1671}
1672
Jiri Pirko6529eab2017-05-17 11:07:55 +02001673static struct tcf_block *cbq_tcf_block(struct Qdisc *sch, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674{
1675 struct cbq_sched_data *q = qdisc_priv(sch);
1676 struct cbq_class *cl = (struct cbq_class *)arg;
1677
1678 if (cl == NULL)
1679 cl = &q->link;
1680
Jiri Pirko6529eab2017-05-17 11:07:55 +02001681 return cl->block;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682}
1683
1684static unsigned long cbq_bind_filter(struct Qdisc *sch, unsigned long parent,
1685 u32 classid)
1686{
1687 struct cbq_sched_data *q = qdisc_priv(sch);
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001688 struct cbq_class *p = (struct cbq_class *)parent;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 struct cbq_class *cl = cbq_class_lookup(q, classid);
1690
1691 if (cl) {
1692 if (p && p->level <= cl->level)
1693 return 0;
1694 cl->filters++;
1695 return (unsigned long)cl;
1696 }
1697 return 0;
1698}
1699
1700static void cbq_unbind_filter(struct Qdisc *sch, unsigned long arg)
1701{
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001702 struct cbq_class *cl = (struct cbq_class *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703
1704 cl->filters--;
1705}
1706
1707static void cbq_walk(struct Qdisc *sch, struct qdisc_walker *arg)
1708{
1709 struct cbq_sched_data *q = qdisc_priv(sch);
Patrick McHardyd77fea22008-07-05 23:22:05 -07001710 struct cbq_class *cl;
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001711 unsigned int h;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712
1713 if (arg->stop)
1714 return;
1715
Patrick McHardyd77fea22008-07-05 23:22:05 -07001716 for (h = 0; h < q->clhash.hashsize; h++) {
Sasha Levinb67bfe02013-02-27 17:06:00 -08001717 hlist_for_each_entry(cl, &q->clhash.hash[h], common.hnode) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 if (arg->count < arg->skip) {
1719 arg->count++;
1720 continue;
1721 }
1722 if (arg->fn(sch, (unsigned long)cl, arg) < 0) {
1723 arg->stop = 1;
1724 return;
1725 }
1726 arg->count++;
1727 }
1728 }
1729}
1730
Eric Dumazet20fea082007-11-14 01:44:41 -08001731static const struct Qdisc_class_ops cbq_class_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 .graft = cbq_graft,
1733 .leaf = cbq_leaf,
Jarek Poplawskia37ef2e2006-12-08 00:25:55 -08001734 .qlen_notify = cbq_qlen_notify,
WANG Cong143976c2017-08-24 16:51:29 -07001735 .find = cbq_find,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 .change = cbq_change_class,
1737 .delete = cbq_delete,
1738 .walk = cbq_walk,
Jiri Pirko6529eab2017-05-17 11:07:55 +02001739 .tcf_block = cbq_tcf_block,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 .bind_tcf = cbq_bind_filter,
1741 .unbind_tcf = cbq_unbind_filter,
1742 .dump = cbq_dump_class,
1743 .dump_stats = cbq_dump_class_stats,
1744};
1745
Eric Dumazet20fea082007-11-14 01:44:41 -08001746static struct Qdisc_ops cbq_qdisc_ops __read_mostly = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 .next = NULL,
1748 .cl_ops = &cbq_class_ops,
1749 .id = "cbq",
1750 .priv_size = sizeof(struct cbq_sched_data),
1751 .enqueue = cbq_enqueue,
1752 .dequeue = cbq_dequeue,
Jarek Poplawski77be1552008-10-31 00:47:01 -07001753 .peek = qdisc_peek_dequeued,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 .init = cbq_init,
1755 .reset = cbq_reset,
1756 .destroy = cbq_destroy,
1757 .change = NULL,
1758 .dump = cbq_dump,
1759 .dump_stats = cbq_dump_stats,
1760 .owner = THIS_MODULE,
1761};
1762
1763static int __init cbq_module_init(void)
1764{
1765 return register_qdisc(&cbq_qdisc_ops);
1766}
YOSHIFUJI Hideaki10297b92007-02-09 23:25:16 +09001767static void __exit cbq_module_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768{
1769 unregister_qdisc(&cbq_qdisc_ops);
1770}
1771module_init(cbq_module_init)
1772module_exit(cbq_module_exit)
1773MODULE_LICENSE("GPL");