blob: 3ec8bec109bbee2014c8b2204906bd123c12fd58 [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
Johannes Bergfceb6432017-04-12 14:34:07 +02001141 err = nla_parse_nested(tb, TCA_CBQ_MAX, opt, cbq_policy, NULL);
Patrick McHardycee63722008-01-23 20:33:32 -08001142 if (err < 0)
1143 return err;
1144
Patrick McHardy27a34212008-01-23 20:35:39 -08001145 if (tb[TCA_CBQ_RTAB] == NULL || tb[TCA_CBQ_RATE] == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 return -EINVAL;
1147
Patrick McHardy1e904742008-01-22 22:11:17 -08001148 r = nla_data(tb[TCA_CBQ_RATE]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149
Patrick McHardy1e904742008-01-22 22:11:17 -08001150 if ((q->link.R_tab = qdisc_get_rtab(r, tb[TCA_CBQ_RTAB])) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 return -EINVAL;
1152
Patrick McHardyd77fea22008-07-05 23:22:05 -07001153 err = qdisc_class_hash_init(&q->clhash);
1154 if (err < 0)
1155 goto put_rtab;
1156
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 q->link.sibling = &q->link;
Patrick McHardyd77fea22008-07-05 23:22:05 -07001158 q->link.common.classid = sch->handle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 q->link.qdisc = sch;
Changli Gao3511c912010-10-16 13:04:08 +00001160 q->link.q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
1161 sch->handle);
1162 if (!q->link.q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 q->link.q = &noop_qdisc;
Jiri Kosina49b49972017-03-08 16:03:32 +01001164 else
1165 qdisc_hash_add(q->link.q, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001167 q->link.priority = TC_CBQ_MAXPRIO - 1;
1168 q->link.priority2 = TC_CBQ_MAXPRIO - 1;
1169 q->link.cpriority = TC_CBQ_MAXPRIO - 1;
David S. Miller5ce2d482008-07-08 17:06:30 -07001170 q->link.allot = psched_mtu(qdisc_dev(sch));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 q->link.quantum = q->link.allot;
1172 q->link.weight = q->link.R_tab->rate.rate;
1173
1174 q->link.ewma_log = TC_CBQ_DEF_EWMA;
1175 q->link.avpkt = q->link.allot/2;
1176 q->link.minidle = -0x7FFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177
Patrick McHardy88a99352007-03-16 01:21:11 -07001178 qdisc_watchdog_init(&q->watchdog, sch);
Eric Dumazet4a8e3202014-09-20 18:01:30 -07001179 hrtimer_init(&q->delay_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 q->delay_timer.function = cbq_undelay;
1181 q->toplevel = TC_CBQ_MAXLEVEL;
Patrick McHardy3bebcda2007-03-23 11:29:25 -07001182 q->now = psched_get_time();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183
1184 cbq_link_class(&q->link);
1185
Patrick McHardy1e904742008-01-22 22:11:17 -08001186 if (tb[TCA_CBQ_LSSOPT])
1187 cbq_set_lss(&q->link, nla_data(tb[TCA_CBQ_LSSOPT]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188
1189 cbq_addprio(q, &q->link);
1190 return 0;
Patrick McHardyd77fea22008-07-05 23:22:05 -07001191
1192put_rtab:
1193 qdisc_put_rtab(q->link.R_tab);
1194 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195}
1196
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001197static int cbq_dump_rate(struct sk_buff *skb, struct cbq_class *cl)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198{
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07001199 unsigned char *b = skb_tail_pointer(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200
David S. Miller1b34ec42012-03-29 05:11:39 -04001201 if (nla_put(skb, TCA_CBQ_RATE, sizeof(cl->R_tab->rate), &cl->R_tab->rate))
1202 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 return skb->len;
1204
Patrick McHardy1e904742008-01-22 22:11:17 -08001205nla_put_failure:
Arnaldo Carvalho de Melodc5fc572007-03-25 23:06:12 -07001206 nlmsg_trim(skb, b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 return -1;
1208}
1209
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001210static int cbq_dump_lss(struct sk_buff *skb, struct cbq_class *cl)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211{
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07001212 unsigned char *b = skb_tail_pointer(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 struct tc_cbq_lssopt opt;
1214
1215 opt.flags = 0;
1216 if (cl->borrow == NULL)
1217 opt.flags |= TCF_CBQ_LSS_BOUNDED;
1218 if (cl->share == NULL)
1219 opt.flags |= TCF_CBQ_LSS_ISOLATED;
1220 opt.ewma_log = cl->ewma_log;
1221 opt.level = cl->level;
1222 opt.avpkt = cl->avpkt;
1223 opt.maxidle = cl->maxidle;
1224 opt.minidle = (u32)(-cl->minidle);
1225 opt.offtime = cl->offtime;
1226 opt.change = ~0;
David S. Miller1b34ec42012-03-29 05:11:39 -04001227 if (nla_put(skb, TCA_CBQ_LSSOPT, sizeof(opt), &opt))
1228 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 return skb->len;
1230
Patrick McHardy1e904742008-01-22 22:11:17 -08001231nla_put_failure:
Arnaldo Carvalho de Melodc5fc572007-03-25 23:06:12 -07001232 nlmsg_trim(skb, b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 return -1;
1234}
1235
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001236static int cbq_dump_wrr(struct sk_buff *skb, struct cbq_class *cl)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237{
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07001238 unsigned char *b = skb_tail_pointer(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 struct tc_cbq_wrropt opt;
1240
David S. Millera0db8562013-07-30 00:16:21 -07001241 memset(&opt, 0, sizeof(opt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 opt.flags = 0;
1243 opt.allot = cl->allot;
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001244 opt.priority = cl->priority + 1;
1245 opt.cpriority = cl->cpriority + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 opt.weight = cl->weight;
David S. Miller1b34ec42012-03-29 05:11:39 -04001247 if (nla_put(skb, TCA_CBQ_WRROPT, sizeof(opt), &opt))
1248 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 return skb->len;
1250
Patrick McHardy1e904742008-01-22 22:11:17 -08001251nla_put_failure:
Arnaldo Carvalho de Melodc5fc572007-03-25 23:06:12 -07001252 nlmsg_trim(skb, b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 return -1;
1254}
1255
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001256static int cbq_dump_fopt(struct sk_buff *skb, struct cbq_class *cl)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257{
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07001258 unsigned char *b = skb_tail_pointer(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 struct tc_cbq_fopt opt;
1260
1261 if (cl->split || cl->defmap) {
Patrick McHardyd77fea22008-07-05 23:22:05 -07001262 opt.split = cl->split ? cl->split->common.classid : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 opt.defmap = cl->defmap;
1264 opt.defchange = ~0;
David S. Miller1b34ec42012-03-29 05:11:39 -04001265 if (nla_put(skb, TCA_CBQ_FOPT, sizeof(opt), &opt))
1266 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 }
1268 return skb->len;
1269
Patrick McHardy1e904742008-01-22 22:11:17 -08001270nla_put_failure:
Arnaldo Carvalho de Melodc5fc572007-03-25 23:06:12 -07001271 nlmsg_trim(skb, b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 return -1;
1273}
1274
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275static int cbq_dump_attr(struct sk_buff *skb, struct cbq_class *cl)
1276{
1277 if (cbq_dump_lss(skb, cl) < 0 ||
1278 cbq_dump_rate(skb, cl) < 0 ||
1279 cbq_dump_wrr(skb, cl) < 0 ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 cbq_dump_fopt(skb, cl) < 0)
1281 return -1;
1282 return 0;
1283}
1284
1285static int cbq_dump(struct Qdisc *sch, struct sk_buff *skb)
1286{
1287 struct cbq_sched_data *q = qdisc_priv(sch);
Patrick McHardy4b3550ef2008-01-23 20:34:11 -08001288 struct nlattr *nest;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289
Patrick McHardy4b3550ef2008-01-23 20:34:11 -08001290 nest = nla_nest_start(skb, TCA_OPTIONS);
1291 if (nest == NULL)
1292 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 if (cbq_dump_attr(skb, &q->link) < 0)
Patrick McHardy1e904742008-01-22 22:11:17 -08001294 goto nla_put_failure;
Yang Yingliangd59b7d82014-03-12 10:20:32 +08001295 return nla_nest_end(skb, nest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296
Patrick McHardy1e904742008-01-22 22:11:17 -08001297nla_put_failure:
Patrick McHardy4b3550ef2008-01-23 20:34:11 -08001298 nla_nest_cancel(skb, nest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 return -1;
1300}
1301
1302static int
1303cbq_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
1304{
1305 struct cbq_sched_data *q = qdisc_priv(sch);
1306
1307 q->link.xstats.avgidle = q->link.avgidle;
1308 return gnet_stats_copy_app(d, &q->link.xstats, sizeof(q->link.xstats));
1309}
1310
1311static int
1312cbq_dump_class(struct Qdisc *sch, unsigned long arg,
1313 struct sk_buff *skb, struct tcmsg *tcm)
1314{
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001315 struct cbq_class *cl = (struct cbq_class *)arg;
Patrick McHardy4b3550ef2008-01-23 20:34:11 -08001316 struct nlattr *nest;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317
1318 if (cl->tparent)
Patrick McHardyd77fea22008-07-05 23:22:05 -07001319 tcm->tcm_parent = cl->tparent->common.classid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 else
1321 tcm->tcm_parent = TC_H_ROOT;
Patrick McHardyd77fea22008-07-05 23:22:05 -07001322 tcm->tcm_handle = cl->common.classid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 tcm->tcm_info = cl->q->handle;
1324
Patrick McHardy4b3550ef2008-01-23 20:34:11 -08001325 nest = nla_nest_start(skb, TCA_OPTIONS);
1326 if (nest == NULL)
1327 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 if (cbq_dump_attr(skb, cl) < 0)
Patrick McHardy1e904742008-01-22 22:11:17 -08001329 goto nla_put_failure;
Yang Yingliangd59b7d82014-03-12 10:20:32 +08001330 return nla_nest_end(skb, nest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331
Patrick McHardy1e904742008-01-22 22:11:17 -08001332nla_put_failure:
Patrick McHardy4b3550ef2008-01-23 20:34:11 -08001333 nla_nest_cancel(skb, nest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 return -1;
1335}
1336
1337static int
1338cbq_dump_class_stats(struct Qdisc *sch, unsigned long arg,
1339 struct gnet_dump *d)
1340{
1341 struct cbq_sched_data *q = qdisc_priv(sch);
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001342 struct cbq_class *cl = (struct cbq_class *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 cl->xstats.avgidle = cl->avgidle;
1345 cl->xstats.undertime = 0;
1346
Patrick McHardya0849802007-03-23 11:28:30 -07001347 if (cl->undertime != PSCHED_PASTPERFECT)
Patrick McHardy8edc0c32007-03-23 11:28:55 -07001348 cl->xstats.undertime = cl->undertime - q->now;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349
Eric Dumazetedb09eb2016-06-06 09:37:16 -07001350 if (gnet_stats_copy_basic(qdisc_root_sleeping_running(sch),
1351 d, NULL, &cl->bstats) < 0 ||
Eric Dumazet1c0d32f2016-12-04 09:48:16 -08001352 gnet_stats_copy_rate_est(d, &cl->rate_est) < 0 ||
John Fastabendb0ab6f92014-09-28 11:54:24 -07001353 gnet_stats_copy_queue(d, NULL, &cl->qstats, cl->q->q.qlen) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 return -1;
1355
1356 return gnet_stats_copy_app(d, &cl->xstats, sizeof(cl->xstats));
1357}
1358
1359static int cbq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
1360 struct Qdisc **old)
1361{
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001362 struct cbq_class *cl = (struct cbq_class *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363
Patrick McHardy5b9a9cc2009-09-04 06:41:17 +00001364 if (new == NULL) {
Changli Gao3511c912010-10-16 13:04:08 +00001365 new = qdisc_create_dflt(sch->dev_queue,
Patrick McHardy5b9a9cc2009-09-04 06:41:17 +00001366 &pfifo_qdisc_ops, cl->common.classid);
1367 if (new == NULL)
1368 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 }
Patrick McHardy5b9a9cc2009-09-04 06:41:17 +00001370
WANG Cong86a79962016-02-25 14:55:00 -08001371 *old = qdisc_replace(sch, new, &cl->q);
Patrick McHardy5b9a9cc2009-09-04 06:41:17 +00001372 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373}
1374
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001375static struct Qdisc *cbq_leaf(struct Qdisc *sch, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376{
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001377 struct cbq_class *cl = (struct cbq_class *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378
Patrick McHardy5b9a9cc2009-09-04 06:41:17 +00001379 return cl->q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380}
1381
Jarek Poplawskia37ef2e2006-12-08 00:25:55 -08001382static void cbq_qlen_notify(struct Qdisc *sch, unsigned long arg)
1383{
1384 struct cbq_class *cl = (struct cbq_class *)arg;
1385
Konstantin Khlebnikov95946652017-08-15 16:39:59 +03001386 cbq_deactivate_class(cl);
Jarek Poplawskia37ef2e2006-12-08 00:25:55 -08001387}
1388
WANG Cong143976c2017-08-24 16:51:29 -07001389static unsigned long cbq_find(struct Qdisc *sch, u32 classid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390{
1391 struct cbq_sched_data *q = qdisc_priv(sch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392
WANG Cong143976c2017-08-24 16:51:29 -07001393 return (unsigned long)cbq_class_lookup(q, classid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394}
1395
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396static void cbq_destroy_class(struct Qdisc *sch, struct cbq_class *cl)
1397{
1398 struct cbq_sched_data *q = qdisc_priv(sch);
1399
Ilpo Järvinen547b7922008-07-25 21:43:18 -07001400 WARN_ON(cl->filters);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401
Jiri Pirko6529eab2017-05-17 11:07:55 +02001402 tcf_block_put(cl->block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 qdisc_destroy(cl->q);
1404 qdisc_put_rtab(cl->R_tab);
Eric Dumazet1c0d32f2016-12-04 09:48:16 -08001405 gen_kill_estimator(&cl->rate_est);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 if (cl != &q->link)
1407 kfree(cl);
1408}
1409
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001410static void cbq_destroy(struct Qdisc *sch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411{
1412 struct cbq_sched_data *q = qdisc_priv(sch);
Sasha Levinb67bfe02013-02-27 17:06:00 -08001413 struct hlist_node *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 struct cbq_class *cl;
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001415 unsigned int h;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416
Patrick McHardyc3bc7cf2007-07-15 00:03:05 -07001417#ifdef CONFIG_NET_CLS_ACT
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 q->rx_class = NULL;
1419#endif
1420 /*
1421 * Filters must be destroyed first because we don't destroy the
1422 * classes from root to leafs which means that filters can still
1423 * be bound to classes which have been destroyed already. --TGR '04
1424 */
Patrick McHardyd77fea22008-07-05 23:22:05 -07001425 for (h = 0; h < q->clhash.hashsize; h++) {
Konstantin Khlebnikov89890422017-08-15 16:35:21 +03001426 hlist_for_each_entry(cl, &q->clhash.hash[h], common.hnode) {
Jiri Pirko6529eab2017-05-17 11:07:55 +02001427 tcf_block_put(cl->block);
Konstantin Khlebnikov89890422017-08-15 16:35:21 +03001428 cl->block = NULL;
1429 }
Patrick McHardyb00b4bf2007-06-05 16:06:59 -07001430 }
Patrick McHardyd77fea22008-07-05 23:22:05 -07001431 for (h = 0; h < q->clhash.hashsize; h++) {
Sasha Levinb67bfe02013-02-27 17:06:00 -08001432 hlist_for_each_entry_safe(cl, next, &q->clhash.hash[h],
Patrick McHardyd77fea22008-07-05 23:22:05 -07001433 common.hnode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 cbq_destroy_class(sch, cl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 }
Patrick McHardyd77fea22008-07-05 23:22:05 -07001436 qdisc_class_hash_destroy(&q->clhash);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437}
1438
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439static int
Patrick McHardy1e904742008-01-22 22:11:17 -08001440cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **tca,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 unsigned long *arg)
1442{
1443 int err;
1444 struct cbq_sched_data *q = qdisc_priv(sch);
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001445 struct cbq_class *cl = (struct cbq_class *)*arg;
Patrick McHardy1e904742008-01-22 22:11:17 -08001446 struct nlattr *opt = tca[TCA_OPTIONS];
1447 struct nlattr *tb[TCA_CBQ_MAX + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 struct cbq_class *parent;
1449 struct qdisc_rate_table *rtab = NULL;
1450
Patrick McHardycee63722008-01-23 20:33:32 -08001451 if (opt == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 return -EINVAL;
1453
Johannes Bergfceb6432017-04-12 14:34:07 +02001454 err = nla_parse_nested(tb, TCA_CBQ_MAX, opt, cbq_policy, NULL);
Patrick McHardycee63722008-01-23 20:33:32 -08001455 if (err < 0)
1456 return err;
1457
Florian Westphaldd47c1f2016-06-09 00:27:40 +02001458 if (tb[TCA_CBQ_OVL_STRATEGY] || tb[TCA_CBQ_POLICE])
Florian Westphalc3498d32016-06-09 00:27:39 +02001459 return -EOPNOTSUPP;
1460
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461 if (cl) {
1462 /* Check parent */
1463 if (parentid) {
Patrick McHardyd77fea22008-07-05 23:22:05 -07001464 if (cl->tparent &&
1465 cl->tparent->common.classid != parentid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 return -EINVAL;
1467 if (!cl->tparent && parentid != TC_H_ROOT)
1468 return -EINVAL;
1469 }
1470
Patrick McHardy1e904742008-01-22 22:11:17 -08001471 if (tb[TCA_CBQ_RATE]) {
Stephen Hemminger71bcb092008-11-25 21:13:31 -08001472 rtab = qdisc_get_rtab(nla_data(tb[TCA_CBQ_RATE]),
1473 tb[TCA_CBQ_RTAB]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 if (rtab == NULL)
1475 return -EINVAL;
1476 }
1477
Stephen Hemminger71bcb092008-11-25 21:13:31 -08001478 if (tca[TCA_RATE]) {
John Fastabend22e0f8b2014-09-28 11:52:56 -07001479 err = gen_replace_estimator(&cl->bstats, NULL,
1480 &cl->rate_est,
Eric Dumazetedb09eb2016-06-06 09:37:16 -07001481 NULL,
1482 qdisc_root_sleeping_running(sch),
Stephen Hemminger71bcb092008-11-25 21:13:31 -08001483 tca[TCA_RATE]);
1484 if (err) {
Yang Yingliang79c11f22013-12-17 15:29:17 +08001485 qdisc_put_rtab(rtab);
Stephen Hemminger71bcb092008-11-25 21:13:31 -08001486 return err;
1487 }
1488 }
1489
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 /* Change class parameters */
1491 sch_tree_lock(sch);
1492
1493 if (cl->next_alive != NULL)
1494 cbq_deactivate_class(cl);
1495
1496 if (rtab) {
Patrick McHardyb94c8af2008-11-20 04:11:36 -08001497 qdisc_put_rtab(cl->R_tab);
1498 cl->R_tab = rtab;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 }
1500
Patrick McHardy1e904742008-01-22 22:11:17 -08001501 if (tb[TCA_CBQ_LSSOPT])
1502 cbq_set_lss(cl, nla_data(tb[TCA_CBQ_LSSOPT]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503
Patrick McHardy1e904742008-01-22 22:11:17 -08001504 if (tb[TCA_CBQ_WRROPT]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 cbq_rmprio(q, cl);
Patrick McHardy1e904742008-01-22 22:11:17 -08001506 cbq_set_wrr(cl, nla_data(tb[TCA_CBQ_WRROPT]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 }
1508
Patrick McHardy1e904742008-01-22 22:11:17 -08001509 if (tb[TCA_CBQ_FOPT])
1510 cbq_set_fopt(cl, nla_data(tb[TCA_CBQ_FOPT]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511
1512 if (cl->q->q.qlen)
1513 cbq_activate_class(cl);
1514
1515 sch_tree_unlock(sch);
1516
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 return 0;
1518 }
1519
1520 if (parentid == TC_H_ROOT)
1521 return -EINVAL;
1522
Patrick McHardy1e904742008-01-22 22:11:17 -08001523 if (tb[TCA_CBQ_WRROPT] == NULL || tb[TCA_CBQ_RATE] == NULL ||
1524 tb[TCA_CBQ_LSSOPT] == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 return -EINVAL;
1526
Patrick McHardy1e904742008-01-22 22:11:17 -08001527 rtab = qdisc_get_rtab(nla_data(tb[TCA_CBQ_RATE]), tb[TCA_CBQ_RTAB]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 if (rtab == NULL)
1529 return -EINVAL;
1530
1531 if (classid) {
1532 err = -EINVAL;
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001533 if (TC_H_MAJ(classid ^ sch->handle) ||
1534 cbq_class_lookup(q, classid))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 goto failure;
1536 } else {
1537 int i;
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001538 classid = TC_H_MAKE(sch->handle, 0x8000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001540 for (i = 0; i < 0x8000; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 if (++q->hgenerator >= 0x8000)
1542 q->hgenerator = 1;
1543 if (cbq_class_lookup(q, classid|q->hgenerator) == NULL)
1544 break;
1545 }
1546 err = -ENOSR;
1547 if (i >= 0x8000)
1548 goto failure;
1549 classid = classid|q->hgenerator;
1550 }
1551
1552 parent = &q->link;
1553 if (parentid) {
1554 parent = cbq_class_lookup(q, parentid);
1555 err = -EINVAL;
1556 if (parent == NULL)
1557 goto failure;
1558 }
1559
1560 err = -ENOBUFS;
Panagiotis Issaris0da974f2006-07-21 14:51:30 -07001561 cl = kzalloc(sizeof(*cl), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 if (cl == NULL)
1563 goto failure;
Stephen Hemminger71bcb092008-11-25 21:13:31 -08001564
Jiri Pirko6529eab2017-05-17 11:07:55 +02001565 err = tcf_block_get(&cl->block, &cl->filter_list);
1566 if (err) {
1567 kfree(cl);
1568 return err;
1569 }
1570
Stephen Hemminger71bcb092008-11-25 21:13:31 -08001571 if (tca[TCA_RATE]) {
John Fastabend22e0f8b2014-09-28 11:52:56 -07001572 err = gen_new_estimator(&cl->bstats, NULL, &cl->rate_est,
Eric Dumazetedb09eb2016-06-06 09:37:16 -07001573 NULL,
1574 qdisc_root_sleeping_running(sch),
Stephen Hemminger71bcb092008-11-25 21:13:31 -08001575 tca[TCA_RATE]);
1576 if (err) {
Jiri Pirko6529eab2017-05-17 11:07:55 +02001577 tcf_block_put(cl->block);
Stephen Hemminger71bcb092008-11-25 21:13:31 -08001578 kfree(cl);
1579 goto failure;
1580 }
1581 }
1582
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 cl->R_tab = rtab;
1584 rtab = NULL;
Changli Gao3511c912010-10-16 13:04:08 +00001585 cl->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, classid);
1586 if (!cl->q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 cl->q = &noop_qdisc;
Jiri Kosina49b49972017-03-08 16:03:32 +01001588 else
1589 qdisc_hash_add(cl->q, true);
1590
Patrick McHardyd77fea22008-07-05 23:22:05 -07001591 cl->common.classid = classid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 cl->tparent = parent;
1593 cl->qdisc = sch;
1594 cl->allot = parent->allot;
1595 cl->quantum = cl->allot;
1596 cl->weight = cl->R_tab->rate.rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597
1598 sch_tree_lock(sch);
1599 cbq_link_class(cl);
1600 cl->borrow = cl->tparent;
1601 if (cl->tparent != &q->link)
1602 cl->share = cl->tparent;
1603 cbq_adjust_levels(parent);
1604 cl->minidle = -0x7FFFFFFF;
Patrick McHardy1e904742008-01-22 22:11:17 -08001605 cbq_set_lss(cl, nla_data(tb[TCA_CBQ_LSSOPT]));
1606 cbq_set_wrr(cl, nla_data(tb[TCA_CBQ_WRROPT]));
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001607 if (cl->ewma_log == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 cl->ewma_log = q->link.ewma_log;
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001609 if (cl->maxidle == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 cl->maxidle = q->link.maxidle;
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001611 if (cl->avpkt == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 cl->avpkt = q->link.avpkt;
Patrick McHardy1e904742008-01-22 22:11:17 -08001613 if (tb[TCA_CBQ_FOPT])
1614 cbq_set_fopt(cl, nla_data(tb[TCA_CBQ_FOPT]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 sch_tree_unlock(sch);
1616
Patrick McHardyd77fea22008-07-05 23:22:05 -07001617 qdisc_class_hash_grow(sch, &q->clhash);
1618
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 *arg = (unsigned long)cl;
1620 return 0;
1621
1622failure:
1623 qdisc_put_rtab(rtab);
1624 return err;
1625}
1626
1627static int cbq_delete(struct Qdisc *sch, unsigned long arg)
1628{
1629 struct cbq_sched_data *q = qdisc_priv(sch);
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001630 struct cbq_class *cl = (struct cbq_class *)arg;
WANG Cong2ccccf52016-02-25 14:55:01 -08001631 unsigned int qlen, backlog;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632
1633 if (cl->filters || cl->children || cl == &q->link)
1634 return -EBUSY;
1635
1636 sch_tree_lock(sch);
1637
Jarek Poplawskia37ef2e2006-12-08 00:25:55 -08001638 qlen = cl->q->q.qlen;
WANG Cong2ccccf52016-02-25 14:55:01 -08001639 backlog = cl->q->qstats.backlog;
Jarek Poplawskia37ef2e2006-12-08 00:25:55 -08001640 qdisc_reset(cl->q);
WANG Cong2ccccf52016-02-25 14:55:01 -08001641 qdisc_tree_reduce_backlog(cl->q, qlen, backlog);
Jarek Poplawskia37ef2e2006-12-08 00:25:55 -08001642
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 if (cl->next_alive)
1644 cbq_deactivate_class(cl);
1645
1646 if (q->tx_borrowed == cl)
1647 q->tx_borrowed = q->tx_class;
1648 if (q->tx_class == cl) {
1649 q->tx_class = NULL;
1650 q->tx_borrowed = NULL;
1651 }
Patrick McHardyc3bc7cf2007-07-15 00:03:05 -07001652#ifdef CONFIG_NET_CLS_ACT
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 if (q->rx_class == cl)
1654 q->rx_class = NULL;
1655#endif
1656
1657 cbq_unlink_class(cl);
1658 cbq_adjust_levels(cl->tparent);
1659 cl->defmap = 0;
1660 cbq_sync_defmap(cl);
1661
1662 cbq_rmprio(q, cl);
1663 sch_tree_unlock(sch);
1664
WANG Cong143976c2017-08-24 16:51:29 -07001665 cbq_destroy_class(sch, cl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 return 0;
1667}
1668
Jiri Pirko6529eab2017-05-17 11:07:55 +02001669static struct tcf_block *cbq_tcf_block(struct Qdisc *sch, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670{
1671 struct cbq_sched_data *q = qdisc_priv(sch);
1672 struct cbq_class *cl = (struct cbq_class *)arg;
1673
1674 if (cl == NULL)
1675 cl = &q->link;
1676
Jiri Pirko6529eab2017-05-17 11:07:55 +02001677 return cl->block;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678}
1679
1680static unsigned long cbq_bind_filter(struct Qdisc *sch, unsigned long parent,
1681 u32 classid)
1682{
1683 struct cbq_sched_data *q = qdisc_priv(sch);
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001684 struct cbq_class *p = (struct cbq_class *)parent;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 struct cbq_class *cl = cbq_class_lookup(q, classid);
1686
1687 if (cl) {
1688 if (p && p->level <= cl->level)
1689 return 0;
1690 cl->filters++;
1691 return (unsigned long)cl;
1692 }
1693 return 0;
1694}
1695
1696static void cbq_unbind_filter(struct Qdisc *sch, unsigned long arg)
1697{
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001698 struct cbq_class *cl = (struct cbq_class *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699
1700 cl->filters--;
1701}
1702
1703static void cbq_walk(struct Qdisc *sch, struct qdisc_walker *arg)
1704{
1705 struct cbq_sched_data *q = qdisc_priv(sch);
Patrick McHardyd77fea22008-07-05 23:22:05 -07001706 struct cbq_class *cl;
Eric Dumazetcc7ec452011-01-19 19:26:56 +00001707 unsigned int h;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708
1709 if (arg->stop)
1710 return;
1711
Patrick McHardyd77fea22008-07-05 23:22:05 -07001712 for (h = 0; h < q->clhash.hashsize; h++) {
Sasha Levinb67bfe02013-02-27 17:06:00 -08001713 hlist_for_each_entry(cl, &q->clhash.hash[h], common.hnode) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 if (arg->count < arg->skip) {
1715 arg->count++;
1716 continue;
1717 }
1718 if (arg->fn(sch, (unsigned long)cl, arg) < 0) {
1719 arg->stop = 1;
1720 return;
1721 }
1722 arg->count++;
1723 }
1724 }
1725}
1726
Eric Dumazet20fea082007-11-14 01:44:41 -08001727static const struct Qdisc_class_ops cbq_class_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 .graft = cbq_graft,
1729 .leaf = cbq_leaf,
Jarek Poplawskia37ef2e2006-12-08 00:25:55 -08001730 .qlen_notify = cbq_qlen_notify,
WANG Cong143976c2017-08-24 16:51:29 -07001731 .find = cbq_find,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 .change = cbq_change_class,
1733 .delete = cbq_delete,
1734 .walk = cbq_walk,
Jiri Pirko6529eab2017-05-17 11:07:55 +02001735 .tcf_block = cbq_tcf_block,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 .bind_tcf = cbq_bind_filter,
1737 .unbind_tcf = cbq_unbind_filter,
1738 .dump = cbq_dump_class,
1739 .dump_stats = cbq_dump_class_stats,
1740};
1741
Eric Dumazet20fea082007-11-14 01:44:41 -08001742static struct Qdisc_ops cbq_qdisc_ops __read_mostly = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 .next = NULL,
1744 .cl_ops = &cbq_class_ops,
1745 .id = "cbq",
1746 .priv_size = sizeof(struct cbq_sched_data),
1747 .enqueue = cbq_enqueue,
1748 .dequeue = cbq_dequeue,
Jarek Poplawski77be1552008-10-31 00:47:01 -07001749 .peek = qdisc_peek_dequeued,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 .init = cbq_init,
1751 .reset = cbq_reset,
1752 .destroy = cbq_destroy,
1753 .change = NULL,
1754 .dump = cbq_dump,
1755 .dump_stats = cbq_dump_stats,
1756 .owner = THIS_MODULE,
1757};
1758
1759static int __init cbq_module_init(void)
1760{
1761 return register_qdisc(&cbq_qdisc_ops);
1762}
YOSHIFUJI Hideaki10297b92007-02-09 23:25:16 +09001763static void __exit cbq_module_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764{
1765 unregister_qdisc(&cbq_qdisc_ops);
1766}
1767module_init(cbq_module_init)
1768module_exit(cbq_module_exit)
1769MODULE_LICENSE("GPL");