Blame view
net/sched/sch_htb.c
42.6 KB
87990467d [HTB]: Lindent |
1 |
/* |
1da177e4c Linux-2.6.12-rc2 |
2 3 4 5 6 7 8 9 10 11 12 13 |
* net/sched/sch_htb.c Hierarchical token bucket, feed tree version * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * Authors: Martin Devera, <devik@cdi.cz> * * Credits (in time order) for older HTB versions: * Stef Coene <stef.coene@docum.org> * HTB support at LARTC mailing list |
10297b993 [NET] SCHED: Fix ... |
14 |
* Ondrej Kraus, <krauso@barr.cz> |
1da177e4c Linux-2.6.12-rc2 |
15 16 17 18 19 20 21 22 23 24 25 26 |
* found missing INIT_QDISC(htb) * Vladimir Smelhaus, Aamer Akhter, Bert Hubert * helped a lot to locate nasty class stall bug * Andi Kleen, Jamal Hadi, Bert Hubert * code review and helpful comments on shaping * Tomasz Wrona, <tw@eter.tym.pl> * created test case so that I was able to fix nasty bug * Wilfried Weissmann * spotted bug in dequeue code and helped with fix * Jiri Fojtasek * fixed requeue routine * and many others. thanks. |
1da177e4c Linux-2.6.12-rc2 |
27 |
*/ |
1da177e4c Linux-2.6.12-rc2 |
28 |
#include <linux/module.h> |
47083fc07 pkt_sched: Change... |
29 |
#include <linux/moduleparam.h> |
1da177e4c Linux-2.6.12-rc2 |
30 31 |
#include <linux/types.h> #include <linux/kernel.h> |
1da177e4c Linux-2.6.12-rc2 |
32 |
#include <linux/string.h> |
1da177e4c Linux-2.6.12-rc2 |
33 |
#include <linux/errno.h> |
1da177e4c Linux-2.6.12-rc2 |
34 35 36 |
#include <linux/skbuff.h> #include <linux/list.h> #include <linux/compiler.h> |
0ba480538 [NET_SCHED]: Remo... |
37 |
#include <linux/rbtree.h> |
1224736d9 pkt_sched: sch_ht... |
38 |
#include <linux/workqueue.h> |
5a0e3ad6a include cleanup: ... |
39 |
#include <linux/slab.h> |
dc5fc579b [NETLINK]: Use nl... |
40 |
#include <net/netlink.h> |
292f1c7ff sch: make htb_rat... |
41 |
#include <net/sch_generic.h> |
1da177e4c Linux-2.6.12-rc2 |
42 |
#include <net/pkt_sched.h> |
1da177e4c Linux-2.6.12-rc2 |
43 44 45 46 47 |
/* HTB algorithm. Author: devik@cdi.cz ======================================================================== HTB is like TBF with multiple classes. It is also similar to CBQ because |
10297b993 [NET] SCHED: Fix ... |
48 |
it allows to assign priority to each class in hierarchy. |
1da177e4c Linux-2.6.12-rc2 |
49 50 51 |
In fact it is another implementation of Floyd's formal sharing. Levels: |
10297b993 [NET] SCHED: Fix ... |
52 |
Each class is assigned level. Leaf has ALWAYS level 0 and root |
1da177e4c Linux-2.6.12-rc2 |
53 54 55 |
classes have level TC_HTB_MAXDEPTH-1. Interior nodes has level one less than their parent. */ |
47083fc07 pkt_sched: Change... |
56 |
static int htb_hysteresis __read_mostly = 0; /* whether to use mode hysteresis for speedup */ |
87990467d [HTB]: Lindent |
57 |
#define HTB_VER 0x30011 /* major must be matched with number suplied by TC as version */ |
1da177e4c Linux-2.6.12-rc2 |
58 59 60 61 |
#if HTB_VER >> 16 != TC_HTB_PROTOVER #error "Mismatched sch_htb.c and pkt_sch.h" #endif |
47083fc07 pkt_sched: Change... |
62 63 64 |
/* Module parameter and sysfs export */ module_param (htb_hysteresis, int, 0640); MODULE_PARM_DESC(htb_hysteresis, "Hysteresis mode, less CPU load, less accurate"); |
64153ce0a net_sched: htb: d... |
65 66 67 |
static int htb_rate_est = 0; /* htb classes have a default rate estimator */ module_param(htb_rate_est, int, 0640); MODULE_PARM_DESC(htb_rate_est, "setup a default rate estimator (4sec 16sec) for htb classes"); |
1da177e4c Linux-2.6.12-rc2 |
68 69 |
/* used internaly to keep status of single class */ enum htb_cmode { |
87990467d [HTB]: Lindent |
70 71 72 |
HTB_CANT_SEND, /* class can't send and can't borrow */ HTB_MAY_BORROW, /* class can't send but may borrow */ HTB_CAN_SEND /* class can send */ |
1da177e4c Linux-2.6.12-rc2 |
73 |
}; |
c9364636d htb: refactor str... |
74 75 76 77 78 79 80 81 82 83 84 85 86 |
struct htb_prio { union { struct rb_root row; struct rb_root feed; }; struct rb_node *ptr; /* When class changes from state 1->2 and disconnects from * parent's feed then we lost ptr value and start from the * first child again. Here we store classid of the * last valid ptr (used when ptr is NULL). */ u32 last_ptr_id; }; |
ca4ec90b3 htb: reorder stru... |
87 88 89 90 |
/* interior & leaf nodes; props specific to leaves are marked L: * To reduce false sharing, place mostly read fields at beginning, * and mostly written ones at the end. */ |
87990467d [HTB]: Lindent |
91 |
struct htb_class { |
f4c1f3e0c net-sched: sch_ht... |
92 |
struct Qdisc_class_common common; |
ca4ec90b3 htb: reorder stru... |
93 94 95 96 |
struct psched_ratecfg rate; struct psched_ratecfg ceil; s64 buffer, cbuffer;/* token bucket depth/rate */ s64 mbuffer; /* max wait time */ |
cbd375567 htb: fix sign ext... |
97 |
u32 prio; /* these two are used only by leaves... */ |
ca4ec90b3 htb: reorder stru... |
98 |
int quantum; /* but stored for parent-to-leaf return */ |
25d8c0d55 net: rcu-ify tcf_... |
99 |
struct tcf_proto __rcu *filter_list; /* class attached filters */ |
ca4ec90b3 htb: reorder stru... |
100 101 102 103 104 105 |
int filter_cnt; int refcnt; /* usage count of this class */ int level; /* our level (see above) */ unsigned int children; struct htb_class *parent; /* parent class */ |
45203a3b3 net_sched: add 64... |
106 |
struct gnet_stats_rate_est64 rate_est; |
1da177e4c Linux-2.6.12-rc2 |
107 |
|
ca4ec90b3 htb: reorder stru... |
108 109 110 111 |
/* * Written often fields */ struct gnet_stats_basic_packed bstats; |
ca4ec90b3 htb: reorder stru... |
112 |
struct tc_htb_xstats xstats; /* our special stats */ |
87990467d [HTB]: Lindent |
113 |
|
ca4ec90b3 htb: reorder stru... |
114 115 116 |
/* token bucket parameters */ s64 tokens, ctokens;/* current number of tokens */ s64 t_c; /* checkpoint time */ |
c19f7a34f pkt_sched: sch_ht... |
117 |
|
87990467d [HTB]: Lindent |
118 119 |
union { struct htb_class_leaf { |
87990467d [HTB]: Lindent |
120 |
struct list_head drop_list; |
c9364636d htb: refactor str... |
121 122 |
int deficit[TC_HTB_MAXDEPTH]; struct Qdisc *q; |
87990467d [HTB]: Lindent |
123 124 |
} leaf; struct htb_class_inner { |
c9364636d htb: refactor str... |
125 |
struct htb_prio clprio[TC_HTB_NUMPRIO]; |
87990467d [HTB]: Lindent |
126 127 |
} inner; } un; |
ca4ec90b3 htb: reorder stru... |
128 |
s64 pq_key; |
87990467d [HTB]: Lindent |
129 |
|
ca4ec90b3 htb: reorder stru... |
130 131 132 133 |
int prio_activity; /* for which prios are we active */ enum htb_cmode cmode; /* current mode of the class */ struct rb_node pq_node; /* node for event queue */ struct rb_node node[TC_HTB_NUMPRIO]; /* node for self or feed tree */ |
338ed9b4d net_sched: sch_ht... |
134 135 |
unsigned int drops ____cacheline_aligned_in_smp; |
1da177e4c Linux-2.6.12-rc2 |
136 |
}; |
c9364636d htb: refactor str... |
137 138 139 140 |
struct htb_level { struct rb_root wait_pq; struct htb_prio hprio[TC_HTB_NUMPRIO]; }; |
87990467d [HTB]: Lindent |
141 |
struct htb_sched { |
f4c1f3e0c net-sched: sch_ht... |
142 |
struct Qdisc_class_hash clhash; |
c9364636d htb: refactor str... |
143 144 |
int defcls; /* class where unclassified flows go to */ int rate2quantum; /* quant = rate / rate2quantum */ |
1da177e4c Linux-2.6.12-rc2 |
145 |
|
c9364636d htb: refactor str... |
146 |
/* filters for qdisc itself */ |
25d8c0d55 net: rcu-ify tcf_... |
147 |
struct tcf_proto __rcu *filter_list; |
1da177e4c Linux-2.6.12-rc2 |
148 |
|
c9364636d htb: refactor str... |
149 150 151 152 |
#define HTB_WARN_TOOMANYEVENTS 0x1 unsigned int warned; /* only one warning */ int direct_qlen; struct work_struct work; |
1da177e4c Linux-2.6.12-rc2 |
153 |
|
c9364636d htb: refactor str... |
154 |
/* non shaped skbs; let them go directly thru */ |
48da34b7a sched: add and us... |
155 |
struct qdisc_skb_head direct_queue; |
c9364636d htb: refactor str... |
156 |
long direct_pkts; |
1da177e4c Linux-2.6.12-rc2 |
157 |
|
c9364636d htb: refactor str... |
158 |
struct qdisc_watchdog watchdog; |
1da177e4c Linux-2.6.12-rc2 |
159 |
|
c9364636d htb: refactor str... |
160 161 |
s64 now; /* cached dequeue time */ struct list_head drops[TC_HTB_NUMPRIO];/* active leaves (for drops) */ |
1da177e4c Linux-2.6.12-rc2 |
162 |
|
c9364636d htb: refactor str... |
163 164 |
/* time of nearest event per level (row) */ s64 near_ev_cache[TC_HTB_MAXDEPTH]; |
87990467d [HTB]: Lindent |
165 |
|
c9364636d htb: refactor str... |
166 |
int row_mask[TC_HTB_MAXDEPTH]; |
e82181de5 pkt_sched: sch_ht... |
167 |
|
c9364636d htb: refactor str... |
168 |
struct htb_level hlevel[TC_HTB_MAXDEPTH]; |
1da177e4c Linux-2.6.12-rc2 |
169 |
}; |
1da177e4c Linux-2.6.12-rc2 |
170 |
/* find class in global hash table using given handle */ |
87990467d [HTB]: Lindent |
171 |
static inline struct htb_class *htb_find(u32 handle, struct Qdisc *sch) |
1da177e4c Linux-2.6.12-rc2 |
172 173 |
{ struct htb_sched *q = qdisc_priv(sch); |
f4c1f3e0c net-sched: sch_ht... |
174 |
struct Qdisc_class_common *clc; |
0cef296da [HTB]: Use hlist ... |
175 |
|
f4c1f3e0c net-sched: sch_ht... |
176 177 |
clc = qdisc_class_find(&q->clhash, handle); if (clc == NULL) |
1da177e4c Linux-2.6.12-rc2 |
178 |
return NULL; |
f4c1f3e0c net-sched: sch_ht... |
179 |
return container_of(clc, struct htb_class, common); |
1da177e4c Linux-2.6.12-rc2 |
180 181 182 183 184 185 186 187 188 189 |
} /** * htb_classify - classify a packet into class * * It returns NULL if the packet should be dropped or -1 if the packet * should be passed directly thru. In all other cases leaf class is returned. * We allow direct class selection by classid in priority. The we examine * filters in qdisc and in inner nodes (if higher filter points to the inner * node). If we end up with classid MAJOR:0 we enqueue the skb into special |
10297b993 [NET] SCHED: Fix ... |
190 |
* internal fifo (direct). These packets then go directly thru. If we still |
25985edce Fix common misspe... |
191 |
* have no valid leaf we try to use MAJOR:default leaf. It still unsuccessful |
1da177e4c Linux-2.6.12-rc2 |
192 193 |
* then finish and return direct queue. */ |
cc7ec456f net_sched: cleanups |
194 |
#define HTB_DIRECT ((struct htb_class *)-1L) |
1da177e4c Linux-2.6.12-rc2 |
195 |
|
87990467d [HTB]: Lindent |
196 197 |
static struct htb_class *htb_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr) |
1da177e4c Linux-2.6.12-rc2 |
198 199 200 201 202 203 204 205 |
{ struct htb_sched *q = qdisc_priv(sch); struct htb_class *cl; struct tcf_result res; struct tcf_proto *tcf; int result; /* allow to select class by setting skb->priority to valid classid; |
cc7ec456f net_sched: cleanups |
206 207 208 |
* note that nfmark can be used too by attaching filter fw with no * rules in it */ |
1da177e4c Linux-2.6.12-rc2 |
209 |
if (skb->priority == sch->handle) |
87990467d [HTB]: Lindent |
210 |
return HTB_DIRECT; /* X:0 (direct flow) selected */ |
cc7ec456f net_sched: cleanups |
211 |
cl = htb_find(skb->priority, sch); |
29824310c sch_htb: let skb-... |
212 213 214 215 |
if (cl) { if (cl->level == 0) return cl; /* Start with inner filter chain if a non-leaf class is selected */ |
25d8c0d55 net: rcu-ify tcf_... |
216 |
tcf = rcu_dereference_bh(cl->filter_list); |
29824310c sch_htb: let skb-... |
217 |
} else { |
25d8c0d55 net: rcu-ify tcf_... |
218 |
tcf = rcu_dereference_bh(q->filter_list); |
29824310c sch_htb: let skb-... |
219 |
} |
1da177e4c Linux-2.6.12-rc2 |
220 |
|
c27f339af net_sched: Add qd... |
221 |
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS; |
3b3ae8802 net: sched: conso... |
222 |
while (tcf && (result = tc_classify(skb, tcf, &res, false)) >= 0) { |
1da177e4c Linux-2.6.12-rc2 |
223 224 225 |
#ifdef CONFIG_NET_CLS_ACT switch (result) { case TC_ACT_QUEUED: |
87990467d [HTB]: Lindent |
226 |
case TC_ACT_STOLEN: |
378a2f090 net_sched: Add qd... |
227 |
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN; |
1da177e4c Linux-2.6.12-rc2 |
228 229 230 |
case TC_ACT_SHOT: return NULL; } |
1da177e4c Linux-2.6.12-rc2 |
231 |
#endif |
cc7ec456f net_sched: cleanups |
232 233 |
cl = (void *)res.class; if (!cl) { |
1da177e4c Linux-2.6.12-rc2 |
234 |
if (res.classid == sch->handle) |
87990467d [HTB]: Lindent |
235 |
return HTB_DIRECT; /* X:0 (direct flow) */ |
cc7ec456f net_sched: cleanups |
236 237 |
cl = htb_find(res.classid, sch); if (!cl) |
87990467d [HTB]: Lindent |
238 |
break; /* filter selected invalid classid */ |
1da177e4c Linux-2.6.12-rc2 |
239 240 |
} if (!cl->level) |
87990467d [HTB]: Lindent |
241 |
return cl; /* we hit leaf; return it */ |
1da177e4c Linux-2.6.12-rc2 |
242 243 |
/* we have got inner class; apply inner filter chain */ |
25d8c0d55 net: rcu-ify tcf_... |
244 |
tcf = rcu_dereference_bh(cl->filter_list); |
1da177e4c Linux-2.6.12-rc2 |
245 246 |
} /* classification failed; try to use default class */ |
87990467d [HTB]: Lindent |
247 |
cl = htb_find(TC_H_MAKE(TC_H_MAJ(sch->handle), q->defcls), sch); |
1da177e4c Linux-2.6.12-rc2 |
248 |
if (!cl || cl->level) |
87990467d [HTB]: Lindent |
249 |
return HTB_DIRECT; /* bad default .. this is safe bet */ |
1da177e4c Linux-2.6.12-rc2 |
250 251 |
return cl; } |
1da177e4c Linux-2.6.12-rc2 |
252 253 254 255 256 257 |
/** * htb_add_to_id_tree - adds class to the round robin list * * Routine adds class to the list (actually tree) sorted by classid. * Make sure that class is not already on such list for given prio. */ |
87990467d [HTB]: Lindent |
258 259 |
static void htb_add_to_id_tree(struct rb_root *root, struct htb_class *cl, int prio) |
1da177e4c Linux-2.6.12-rc2 |
260 261 |
{ struct rb_node **p = &root->rb_node, *parent = NULL; |
3bf72957d [HTB]: Remove bro... |
262 |
|
1da177e4c Linux-2.6.12-rc2 |
263 |
while (*p) { |
87990467d [HTB]: Lindent |
264 265 |
struct htb_class *c; parent = *p; |
1da177e4c Linux-2.6.12-rc2 |
266 |
c = rb_entry(parent, struct htb_class, node[prio]); |
3bf72957d [HTB]: Remove bro... |
267 |
|
f4c1f3e0c net-sched: sch_ht... |
268 |
if (cl->common.classid > c->common.classid) |
1da177e4c Linux-2.6.12-rc2 |
269 |
p = &parent->rb_right; |
87990467d [HTB]: Lindent |
270 |
else |
1da177e4c Linux-2.6.12-rc2 |
271 272 273 274 275 276 277 278 279 280 281 282 283 |
p = &parent->rb_left; } rb_link_node(&cl->node[prio], parent, p); rb_insert_color(&cl->node[prio], root); } /** * htb_add_to_wait_tree - adds class to the event queue with delay * * The class is added to priority event queue to indicate that class will * change its mode in cl->pq_key microseconds. Make sure that class is not * already in the queue. */ |
87990467d [HTB]: Lindent |
284 |
static void htb_add_to_wait_tree(struct htb_sched *q, |
56b765b79 htb: improved acc... |
285 |
struct htb_class *cl, s64 delay) |
1da177e4c Linux-2.6.12-rc2 |
286 |
{ |
c9364636d htb: refactor str... |
287 |
struct rb_node **p = &q->hlevel[cl->level].wait_pq.rb_node, *parent = NULL; |
3bf72957d [HTB]: Remove bro... |
288 |
|
fb983d457 [NET_SCHED]: sch_... |
289 290 |
cl->pq_key = q->now + delay; if (cl->pq_key == q->now) |
1da177e4c Linux-2.6.12-rc2 |
291 292 293 |
cl->pq_key++; /* update the nearest event cache */ |
fb983d457 [NET_SCHED]: sch_... |
294 |
if (q->near_ev_cache[cl->level] > cl->pq_key) |
1da177e4c Linux-2.6.12-rc2 |
295 |
q->near_ev_cache[cl->level] = cl->pq_key; |
87990467d [HTB]: Lindent |
296 |
|
1da177e4c Linux-2.6.12-rc2 |
297 |
while (*p) { |
87990467d [HTB]: Lindent |
298 299 |
struct htb_class *c; parent = *p; |
1da177e4c Linux-2.6.12-rc2 |
300 |
c = rb_entry(parent, struct htb_class, pq_node); |
fb983d457 [NET_SCHED]: sch_... |
301 |
if (cl->pq_key >= c->pq_key) |
1da177e4c Linux-2.6.12-rc2 |
302 |
p = &parent->rb_right; |
87990467d [HTB]: Lindent |
303 |
else |
1da177e4c Linux-2.6.12-rc2 |
304 305 306 |
p = &parent->rb_left; } rb_link_node(&cl->pq_node, parent, p); |
c9364636d htb: refactor str... |
307 |
rb_insert_color(&cl->pq_node, &q->hlevel[cl->level].wait_pq); |
1da177e4c Linux-2.6.12-rc2 |
308 309 310 311 312 313 314 315 |
} /** * htb_next_rb_node - finds next node in binary tree * * When we are past last key we return NULL. * Average complexity is 2 steps per call. */ |
3696f625e [HTB]: rbtree cle... |
316 |
static inline void htb_next_rb_node(struct rb_node **n) |
1da177e4c Linux-2.6.12-rc2 |
317 318 319 320 321 322 323 324 325 326 |
{ *n = rb_next(*n); } /** * htb_add_class_to_row - add class to its row * * The class is added to row at priorities marked in mask. * It does nothing if mask == 0. */ |
87990467d [HTB]: Lindent |
327 328 |
static inline void htb_add_class_to_row(struct htb_sched *q, struct htb_class *cl, int mask) |
1da177e4c Linux-2.6.12-rc2 |
329 |
{ |
1da177e4c Linux-2.6.12-rc2 |
330 331 332 333 |
q->row_mask[cl->level] |= mask; while (mask) { int prio = ffz(~mask); mask &= ~(1 << prio); |
c9364636d htb: refactor str... |
334 |
htb_add_to_id_tree(&q->hlevel[cl->level].hprio[prio].row, cl, prio); |
1da177e4c Linux-2.6.12-rc2 |
335 336 |
} } |
3696f625e [HTB]: rbtree cle... |
337 338 339 |
/* If this triggers, it is a bug in this code, but it need not be fatal */ static void htb_safe_rb_erase(struct rb_node *rb, struct rb_root *root) { |
81771b3b2 [NET_SCHED]: Reve... |
340 |
if (RB_EMPTY_NODE(rb)) { |
3696f625e [HTB]: rbtree cle... |
341 342 343 344 345 346 |
WARN_ON(1); } else { rb_erase(rb, root); RB_CLEAR_NODE(rb); } } |
1da177e4c Linux-2.6.12-rc2 |
347 348 349 350 351 352 |
/** * htb_remove_class_from_row - removes class from its row * * The class is removed from row at priorities marked in mask. * It does nothing if mask == 0. */ |
87990467d [HTB]: Lindent |
353 354 |
static inline void htb_remove_class_from_row(struct htb_sched *q, struct htb_class *cl, int mask) |
1da177e4c Linux-2.6.12-rc2 |
355 356 |
{ int m = 0; |
c9364636d htb: refactor str... |
357 |
struct htb_level *hlevel = &q->hlevel[cl->level]; |
3bf72957d [HTB]: Remove bro... |
358 |
|
1da177e4c Linux-2.6.12-rc2 |
359 360 |
while (mask) { int prio = ffz(~mask); |
c9364636d htb: refactor str... |
361 |
struct htb_prio *hprio = &hlevel->hprio[prio]; |
3696f625e [HTB]: rbtree cle... |
362 |
|
1da177e4c Linux-2.6.12-rc2 |
363 |
mask &= ~(1 << prio); |
c9364636d htb: refactor str... |
364 365 |
if (hprio->ptr == cl->node + prio) htb_next_rb_node(&hprio->ptr); |
3696f625e [HTB]: rbtree cle... |
366 |
|
c9364636d htb: refactor str... |
367 368 |
htb_safe_rb_erase(cl->node + prio, &hprio->row); if (!hprio->row.rb_node) |
1da177e4c Linux-2.6.12-rc2 |
369 370 |
m |= 1 << prio; } |
1da177e4c Linux-2.6.12-rc2 |
371 372 373 374 375 376 377 |
q->row_mask[cl->level] &= ~m; } /** * htb_activate_prios - creates active classe's feed chain * * The class is connected to ancestors and/or appropriate rows |
10297b993 [NET] SCHED: Fix ... |
378 |
* for priorities it is participating on. cl->cmode must be new |
1da177e4c Linux-2.6.12-rc2 |
379 380 |
* (activated) mode. It does nothing if cl->prio_activity == 0. */ |
87990467d [HTB]: Lindent |
381 |
static void htb_activate_prios(struct htb_sched *q, struct htb_class *cl) |
1da177e4c Linux-2.6.12-rc2 |
382 383 |
{ struct htb_class *p = cl->parent; |
87990467d [HTB]: Lindent |
384 |
long m, mask = cl->prio_activity; |
1da177e4c Linux-2.6.12-rc2 |
385 386 |
while (cl->cmode == HTB_MAY_BORROW && p && mask) { |
87990467d [HTB]: Lindent |
387 388 |
m = mask; while (m) { |
1da177e4c Linux-2.6.12-rc2 |
389 390 |
int prio = ffz(~m); m &= ~(1 << prio); |
87990467d [HTB]: Lindent |
391 |
|
c9364636d htb: refactor str... |
392 |
if (p->un.inner.clprio[prio].feed.rb_node) |
1da177e4c Linux-2.6.12-rc2 |
393 |
/* parent already has its feed in use so that |
cc7ec456f net_sched: cleanups |
394 395 |
* reset bit in mask as parent is already ok */ |
1da177e4c Linux-2.6.12-rc2 |
396 |
mask &= ~(1 << prio); |
87990467d [HTB]: Lindent |
397 |
|
c9364636d htb: refactor str... |
398 |
htb_add_to_id_tree(&p->un.inner.clprio[prio].feed, cl, prio); |
1da177e4c Linux-2.6.12-rc2 |
399 |
} |
1da177e4c Linux-2.6.12-rc2 |
400 |
p->prio_activity |= mask; |
87990467d [HTB]: Lindent |
401 402 |
cl = p; p = cl->parent; |
3bf72957d [HTB]: Remove bro... |
403 |
|
1da177e4c Linux-2.6.12-rc2 |
404 405 |
} if (cl->cmode == HTB_CAN_SEND && mask) |
87990467d [HTB]: Lindent |
406 |
htb_add_class_to_row(q, cl, mask); |
1da177e4c Linux-2.6.12-rc2 |
407 408 409 410 411 |
} /** * htb_deactivate_prios - remove class from feed chain * |
10297b993 [NET] SCHED: Fix ... |
412 |
* cl->cmode must represent old mode (before deactivation). It does |
1da177e4c Linux-2.6.12-rc2 |
413 414 415 416 417 418 |
* nothing if cl->prio_activity == 0. Class is removed from all feed * chains and rows. */ static void htb_deactivate_prios(struct htb_sched *q, struct htb_class *cl) { struct htb_class *p = cl->parent; |
87990467d [HTB]: Lindent |
419 |
long m, mask = cl->prio_activity; |
1da177e4c Linux-2.6.12-rc2 |
420 421 |
while (cl->cmode == HTB_MAY_BORROW && p && mask) { |
87990467d [HTB]: Lindent |
422 423 |
m = mask; mask = 0; |
1da177e4c Linux-2.6.12-rc2 |
424 425 426 |
while (m) { int prio = ffz(~m); m &= ~(1 << prio); |
87990467d [HTB]: Lindent |
427 |
|
c9364636d htb: refactor str... |
428 |
if (p->un.inner.clprio[prio].ptr == cl->node + prio) { |
1da177e4c Linux-2.6.12-rc2 |
429 |
/* we are removing child which is pointed to from |
cc7ec456f net_sched: cleanups |
430 431 432 |
* parent feed - forget the pointer but remember * classid */ |
c9364636d htb: refactor str... |
433 434 |
p->un.inner.clprio[prio].last_ptr_id = cl->common.classid; p->un.inner.clprio[prio].ptr = NULL; |
1da177e4c Linux-2.6.12-rc2 |
435 |
} |
87990467d [HTB]: Lindent |
436 |
|
c9364636d htb: refactor str... |
437 438 |
htb_safe_rb_erase(cl->node + prio, &p->un.inner.clprio[prio].feed); |
87990467d [HTB]: Lindent |
439 |
|
c9364636d htb: refactor str... |
440 |
if (!p->un.inner.clprio[prio].feed.rb_node) |
1da177e4c Linux-2.6.12-rc2 |
441 442 |
mask |= 1 << prio; } |
3bf72957d [HTB]: Remove bro... |
443 |
|
1da177e4c Linux-2.6.12-rc2 |
444 |
p->prio_activity &= ~mask; |
87990467d [HTB]: Lindent |
445 446 |
cl = p; p = cl->parent; |
3bf72957d [HTB]: Remove bro... |
447 |
|
1da177e4c Linux-2.6.12-rc2 |
448 |
} |
87990467d [HTB]: Lindent |
449 450 |
if (cl->cmode == HTB_CAN_SEND && mask) htb_remove_class_from_row(q, cl, mask); |
1da177e4c Linux-2.6.12-rc2 |
451 |
} |
56b765b79 htb: improved acc... |
452 |
static inline s64 htb_lowater(const struct htb_class *cl) |
18a63e868 [HTB]: HTB_HYSTER... |
453 |
{ |
47083fc07 pkt_sched: Change... |
454 455 456 457 |
if (htb_hysteresis) return cl->cmode != HTB_CANT_SEND ? -cl->cbuffer : 0; else return 0; |
18a63e868 [HTB]: HTB_HYSTER... |
458 |
} |
56b765b79 htb: improved acc... |
459 |
static inline s64 htb_hiwater(const struct htb_class *cl) |
18a63e868 [HTB]: HTB_HYSTER... |
460 |
{ |
47083fc07 pkt_sched: Change... |
461 462 463 464 |
if (htb_hysteresis) return cl->cmode == HTB_CAN_SEND ? -cl->buffer : 0; else return 0; |
18a63e868 [HTB]: HTB_HYSTER... |
465 |
} |
47083fc07 pkt_sched: Change... |
466 |
|
18a63e868 [HTB]: HTB_HYSTER... |
467 |
|
1da177e4c Linux-2.6.12-rc2 |
468 469 470 471 472 |
/** * htb_class_mode - computes and returns current class mode * * It computes cl's mode at time cl->t_c+diff and returns it. If mode * is not HTB_CAN_SEND then cl->pq_key is updated to time difference |
10297b993 [NET] SCHED: Fix ... |
473 |
* from now to time when cl will change its state. |
1da177e4c Linux-2.6.12-rc2 |
474 |
* Also it is worth to note that class mode doesn't change simply |
10297b993 [NET] SCHED: Fix ... |
475 |
* at cl->{c,}tokens == 0 but there can rather be hysteresis of |
1da177e4c Linux-2.6.12-rc2 |
476 477 478 |
* 0 .. -cl->{c,}buffer range. It is meant to limit number of * mode transitions per time unit. The speed gain is about 1/6. */ |
87990467d [HTB]: Lindent |
479 |
static inline enum htb_cmode |
56b765b79 htb: improved acc... |
480 |
htb_class_mode(struct htb_class *cl, s64 *diff) |
1da177e4c Linux-2.6.12-rc2 |
481 |
{ |
56b765b79 htb: improved acc... |
482 |
s64 toks; |
1da177e4c Linux-2.6.12-rc2 |
483 |
|
87990467d [HTB]: Lindent |
484 485 486 487 |
if ((toks = (cl->ctokens + *diff)) < htb_lowater(cl)) { *diff = -toks; return HTB_CANT_SEND; } |
18a63e868 [HTB]: HTB_HYSTER... |
488 |
|
87990467d [HTB]: Lindent |
489 490 |
if ((toks = (cl->tokens + *diff)) >= htb_hiwater(cl)) return HTB_CAN_SEND; |
1da177e4c Linux-2.6.12-rc2 |
491 |
|
87990467d [HTB]: Lindent |
492 493 |
*diff = -toks; return HTB_MAY_BORROW; |
1da177e4c Linux-2.6.12-rc2 |
494 495 496 497 498 499 500 501 502 503 504 |
} /** * htb_change_class_mode - changes classe's mode * * This should be the only way how to change classe's mode under normal * cirsumstances. Routine will update feed lists linkage, change mode * and add class to the wait event queue if appropriate. New mode should * be different from old one and cl->pq_key has to be valid if changing * to mode other than HTB_CAN_SEND (see htb_add_to_wait_tree). */ |
87990467d [HTB]: Lindent |
505 |
static void |
56b765b79 htb: improved acc... |
506 |
htb_change_class_mode(struct htb_sched *q, struct htb_class *cl, s64 *diff) |
87990467d [HTB]: Lindent |
507 508 |
{ enum htb_cmode new_mode = htb_class_mode(cl, diff); |
1da177e4c Linux-2.6.12-rc2 |
509 510 |
if (new_mode == cl->cmode) |
87990467d [HTB]: Lindent |
511 512 513 514 515 |
return; if (cl->prio_activity) { /* not necessary: speed optimization */ if (cl->cmode != HTB_CANT_SEND) htb_deactivate_prios(q, cl); |
1da177e4c Linux-2.6.12-rc2 |
516 |
cl->cmode = new_mode; |
87990467d [HTB]: Lindent |
517 518 519 |
if (new_mode != HTB_CANT_SEND) htb_activate_prios(q, cl); } else |
1da177e4c Linux-2.6.12-rc2 |
520 521 522 523 |
cl->cmode = new_mode; } /** |
10297b993 [NET] SCHED: Fix ... |
524 |
* htb_activate - inserts leaf cl into appropriate active feeds |
1da177e4c Linux-2.6.12-rc2 |
525 526 527 528 529 |
* * Routine learns (new) priority of leaf and activates feed chain * for the prio. It can be called on already active leaf safely. * It also adds leaf into droplist. */ |
87990467d [HTB]: Lindent |
530 |
static inline void htb_activate(struct htb_sched *q, struct htb_class *cl) |
1da177e4c Linux-2.6.12-rc2 |
531 |
{ |
547b792ca net: convert BUG_... |
532 |
WARN_ON(cl->level || !cl->un.leaf.q || !cl->un.leaf.q->q.qlen); |
3bf72957d [HTB]: Remove bro... |
533 |
|
1da177e4c Linux-2.6.12-rc2 |
534 |
if (!cl->prio_activity) { |
c19f7a34f pkt_sched: sch_ht... |
535 |
cl->prio_activity = 1 << cl->prio; |
87990467d [HTB]: Lindent |
536 537 |
htb_activate_prios(q, cl); list_add_tail(&cl->un.leaf.drop_list, |
c19f7a34f pkt_sched: sch_ht... |
538 |
q->drops + cl->prio); |
1da177e4c Linux-2.6.12-rc2 |
539 540 541 542 |
} } /** |
10297b993 [NET] SCHED: Fix ... |
543 |
* htb_deactivate - remove leaf cl from active feeds |
1da177e4c Linux-2.6.12-rc2 |
544 545 546 547 |
* * Make sure that leaf is active. In the other words it can't be called * with non-active leaf. It also removes class from the drop list. */ |
87990467d [HTB]: Lindent |
548 |
static inline void htb_deactivate(struct htb_sched *q, struct htb_class *cl) |
1da177e4c Linux-2.6.12-rc2 |
549 |
{ |
547b792ca net: convert BUG_... |
550 |
WARN_ON(!cl->prio_activity); |
3bf72957d [HTB]: Remove bro... |
551 |
|
87990467d [HTB]: Lindent |
552 |
htb_deactivate_prios(q, cl); |
1da177e4c Linux-2.6.12-rc2 |
553 554 555 |
cl->prio_activity = 0; list_del_init(&cl->un.leaf.drop_list); } |
48da34b7a sched: add and us... |
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 |
static void htb_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch, struct qdisc_skb_head *qh) { struct sk_buff *last = qh->tail; if (last) { skb->next = NULL; last->next = skb; qh->tail = skb; } else { qh->tail = skb; qh->head = skb; } qh->qlen++; } |
520ac30f4 net_sched: drop p... |
571 572 |
static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) |
1da177e4c Linux-2.6.12-rc2 |
573 |
{ |
f30ab418a pkt_sched: Remove... |
574 |
int uninitialized_var(ret); |
87990467d [HTB]: Lindent |
575 576 577 578 579 580 |
struct htb_sched *q = qdisc_priv(sch); struct htb_class *cl = htb_classify(skb, sch, &ret); if (cl == HTB_DIRECT) { /* enqueue to helper queue */ if (q->direct_queue.qlen < q->direct_qlen) { |
48da34b7a sched: add and us... |
581 |
htb_enqueue_tail(skb, sch, &q->direct_queue); |
87990467d [HTB]: Lindent |
582 583 |
q->direct_pkts++; } else { |
520ac30f4 net_sched: drop p... |
584 |
return qdisc_drop(skb, sch, to_free); |
87990467d [HTB]: Lindent |
585 |
} |
1da177e4c Linux-2.6.12-rc2 |
586 |
#ifdef CONFIG_NET_CLS_ACT |
87990467d [HTB]: Lindent |
587 |
} else if (!cl) { |
c27f339af net_sched: Add qd... |
588 |
if (ret & __NET_XMIT_BYPASS) |
25331d6ce net: sched: imple... |
589 |
qdisc_qstats_drop(sch); |
520ac30f4 net_sched: drop p... |
590 |
__qdisc_drop(skb, to_free); |
87990467d [HTB]: Lindent |
591 |
return ret; |
1da177e4c Linux-2.6.12-rc2 |
592 |
#endif |
520ac30f4 net_sched: drop p... |
593 594 |
} else if ((ret = qdisc_enqueue(skb, cl->un.leaf.q, to_free)) != NET_XMIT_SUCCESS) { |
378a2f090 net_sched: Add qd... |
595 |
if (net_xmit_drop_count(ret)) { |
25331d6ce net: sched: imple... |
596 |
qdisc_qstats_drop(sch); |
338ed9b4d net_sched: sch_ht... |
597 |
cl->drops++; |
378a2f090 net_sched: Add qd... |
598 |
} |
69747650c pkt_sched: Fix re... |
599 |
return ret; |
87990467d [HTB]: Lindent |
600 |
} else { |
87990467d [HTB]: Lindent |
601 602 |
htb_activate(q, cl); } |
431e3a8e3 sch_htb: update b... |
603 |
qdisc_qstats_backlog_inc(sch, skb); |
87990467d [HTB]: Lindent |
604 |
sch->q.qlen++; |
87990467d [HTB]: Lindent |
605 |
return NET_XMIT_SUCCESS; |
1da177e4c Linux-2.6.12-rc2 |
606 |
} |
56b765b79 htb: improved acc... |
607 |
static inline void htb_accnt_tokens(struct htb_class *cl, int bytes, s64 diff) |
59e4220a1 pkt_sched: sch_ht... |
608 |
{ |
56b765b79 htb: improved acc... |
609 |
s64 toks = diff + cl->tokens; |
59e4220a1 pkt_sched: sch_ht... |
610 611 612 |
if (toks > cl->buffer) toks = cl->buffer; |
292f1c7ff sch: make htb_rat... |
613 |
toks -= (s64) psched_l2t_ns(&cl->rate, bytes); |
59e4220a1 pkt_sched: sch_ht... |
614 615 616 617 618 |
if (toks <= -cl->mbuffer) toks = 1 - cl->mbuffer; cl->tokens = toks; } |
56b765b79 htb: improved acc... |
619 |
static inline void htb_accnt_ctokens(struct htb_class *cl, int bytes, s64 diff) |
59e4220a1 pkt_sched: sch_ht... |
620 |
{ |
56b765b79 htb: improved acc... |
621 |
s64 toks = diff + cl->ctokens; |
59e4220a1 pkt_sched: sch_ht... |
622 623 624 |
if (toks > cl->cbuffer) toks = cl->cbuffer; |
292f1c7ff sch: make htb_rat... |
625 |
toks -= (s64) psched_l2t_ns(&cl->ceil, bytes); |
59e4220a1 pkt_sched: sch_ht... |
626 627 628 629 630 |
if (toks <= -cl->mbuffer) toks = 1 - cl->mbuffer; cl->ctokens = toks; } |
1da177e4c Linux-2.6.12-rc2 |
631 632 633 634 635 636 637 638 639 640 641 |
/** * htb_charge_class - charges amount "bytes" to leaf and ancestors * * Routine assumes that packet "bytes" long was dequeued from leaf cl * borrowing from "level". It accounts bytes to ceil leaky bucket for * leaf and all ancestors and to rate bucket for ancestors at levels * "level" and higher. It also handles possible change of mode resulting * from the update. Note that mode can also increase here (MAY_BORROW to * CAN_SEND) because we can use more precise clock that event queue here. * In such case we remove class from event queue first. */ |
87990467d [HTB]: Lindent |
642 |
static void htb_charge_class(struct htb_sched *q, struct htb_class *cl, |
c9726d689 [NET_SCHED]: Make... |
643 |
int level, struct sk_buff *skb) |
87990467d [HTB]: Lindent |
644 |
{ |
0abf77e55 net_sched: Add ac... |
645 |
int bytes = qdisc_pkt_len(skb); |
1da177e4c Linux-2.6.12-rc2 |
646 |
enum htb_cmode old_mode; |
56b765b79 htb: improved acc... |
647 |
s64 diff; |
1da177e4c Linux-2.6.12-rc2 |
648 649 |
while (cl) { |
56b765b79 htb: improved acc... |
650 |
diff = min_t(s64, q->now - cl->t_c, cl->mbuffer); |
1da177e4c Linux-2.6.12-rc2 |
651 |
if (cl->level >= level) { |
87990467d [HTB]: Lindent |
652 653 |
if (cl->level == level) cl->xstats.lends++; |
59e4220a1 pkt_sched: sch_ht... |
654 |
htb_accnt_tokens(cl, bytes, diff); |
1da177e4c Linux-2.6.12-rc2 |
655 656 |
} else { cl->xstats.borrows++; |
87990467d [HTB]: Lindent |
657 |
cl->tokens += diff; /* we moved t_c; update tokens */ |
1da177e4c Linux-2.6.12-rc2 |
658 |
} |
59e4220a1 pkt_sched: sch_ht... |
659 |
htb_accnt_ctokens(cl, bytes, diff); |
1da177e4c Linux-2.6.12-rc2 |
660 |
cl->t_c = q->now; |
1da177e4c Linux-2.6.12-rc2 |
661 |
|
87990467d [HTB]: Lindent |
662 663 664 |
old_mode = cl->cmode; diff = 0; htb_change_class_mode(q, cl, &diff); |
1da177e4c Linux-2.6.12-rc2 |
665 666 |
if (old_mode != cl->cmode) { if (old_mode != HTB_CAN_SEND) |
c9364636d htb: refactor str... |
667 |
htb_safe_rb_erase(&cl->pq_node, &q->hlevel[cl->level].wait_pq); |
1da177e4c Linux-2.6.12-rc2 |
668 |
if (cl->cmode != HTB_CAN_SEND) |
87990467d [HTB]: Lindent |
669 |
htb_add_to_wait_tree(q, cl, diff); |
1da177e4c Linux-2.6.12-rc2 |
670 |
} |
1da177e4c Linux-2.6.12-rc2 |
671 |
|
bfe0d0298 net_sched: factor... |
672 673 674 |
/* update basic stats except for leaves which are already updated */ if (cl->level) bstats_update(&cl->bstats, skb); |
1da177e4c Linux-2.6.12-rc2 |
675 676 677 678 679 680 681 |
cl = cl->parent; } } /** * htb_do_events - make mode changes to classes at the level * |
fb983d457 [NET_SCHED]: sch_... |
682 |
* Scans event queue for pending events and applies them. Returns time of |
1224736d9 pkt_sched: sch_ht... |
683 |
* next pending event (0 for no event in pq, q->now for too many events). |
fb983d457 [NET_SCHED]: sch_... |
684 |
* Note: Applied are events whose have cl->pq_key <= q->now. |
1da177e4c Linux-2.6.12-rc2 |
685 |
*/ |
c9364636d htb: refactor str... |
686 |
static s64 htb_do_events(struct htb_sched *q, const int level, |
5343a7f8b net_sched: htb: d... |
687 |
unsigned long start) |
1da177e4c Linux-2.6.12-rc2 |
688 |
{ |
8f3ea33a5 sch_htb: fix "too... |
689 |
/* don't run for longer than 2 jiffies; 2 is used instead of |
cc7ec456f net_sched: cleanups |
690 691 692 |
* 1 to simplify things when jiffy is going to be incremented * too soon */ |
a73be0406 pkt_sched: sch_ht... |
693 |
unsigned long stop_at = start + 2; |
c9364636d htb: refactor str... |
694 |
struct rb_root *wait_pq = &q->hlevel[level].wait_pq; |
8f3ea33a5 sch_htb: fix "too... |
695 |
while (time_before(jiffies, stop_at)) { |
1da177e4c Linux-2.6.12-rc2 |
696 |
struct htb_class *cl; |
56b765b79 htb: improved acc... |
697 |
s64 diff; |
c9364636d htb: refactor str... |
698 |
struct rb_node *p = rb_first(wait_pq); |
30bdbe397 [PKT_SCHED] sch_h... |
699 |
|
87990467d [HTB]: Lindent |
700 701 |
if (!p) return 0; |
1da177e4c Linux-2.6.12-rc2 |
702 703 |
cl = rb_entry(p, struct htb_class, pq_node); |
fb983d457 [NET_SCHED]: sch_... |
704 705 |
if (cl->pq_key > q->now) return cl->pq_key; |
c9364636d htb: refactor str... |
706 |
htb_safe_rb_erase(p, wait_pq); |
56b765b79 htb: improved acc... |
707 |
diff = min_t(s64, q->now - cl->t_c, cl->mbuffer); |
87990467d [HTB]: Lindent |
708 |
htb_change_class_mode(q, cl, &diff); |
1da177e4c Linux-2.6.12-rc2 |
709 |
if (cl->cmode != HTB_CAN_SEND) |
87990467d [HTB]: Lindent |
710 |
htb_add_to_wait_tree(q, cl, diff); |
1da177e4c Linux-2.6.12-rc2 |
711 |
} |
1224736d9 pkt_sched: sch_ht... |
712 713 |
/* too much load - let's continue after a break for scheduling */ |
e82181de5 pkt_sched: sch_ht... |
714 |
if (!(q->warned & HTB_WARN_TOOMANYEVENTS)) { |
c17988a90 net_sched: replac... |
715 716 |
pr_warn("htb: too many events! "); |
e82181de5 pkt_sched: sch_ht... |
717 718 |
q->warned |= HTB_WARN_TOOMANYEVENTS; } |
1224736d9 pkt_sched: sch_ht... |
719 720 |
return q->now; |
1da177e4c Linux-2.6.12-rc2 |
721 722 723 |
} /* Returns class->node+prio from id-tree where classe's id is >= id. NULL |
cc7ec456f net_sched: cleanups |
724 725 |
* is no such one exists. */ |
87990467d [HTB]: Lindent |
726 727 |
static struct rb_node *htb_id_find_next_upper(int prio, struct rb_node *n, u32 id) |
1da177e4c Linux-2.6.12-rc2 |
728 729 730 |
{ struct rb_node *r = NULL; while (n) { |
87990467d [HTB]: Lindent |
731 732 |
struct htb_class *cl = rb_entry(n, struct htb_class, node[prio]); |
87990467d [HTB]: Lindent |
733 |
|
f4c1f3e0c net-sched: sch_ht... |
734 |
if (id > cl->common.classid) { |
1da177e4c Linux-2.6.12-rc2 |
735 |
n = n->rb_right; |
1b5c0077e pkt_sched: sch_ht... |
736 |
} else if (id < cl->common.classid) { |
1da177e4c Linux-2.6.12-rc2 |
737 738 |
r = n; n = n->rb_left; |
1b5c0077e pkt_sched: sch_ht... |
739 740 |
} else { return n; |
1da177e4c Linux-2.6.12-rc2 |
741 742 743 744 745 746 747 748 749 750 |
} } return r; } /** * htb_lookup_leaf - returns next leaf class in DRR order * * Find leaf where current feed pointers points to. */ |
c9364636d htb: refactor str... |
751 |
static struct htb_class *htb_lookup_leaf(struct htb_prio *hprio, const int prio) |
1da177e4c Linux-2.6.12-rc2 |
752 753 754 755 756 757 |
{ int i; struct { struct rb_node *root; struct rb_node **pptr; u32 *pid; |
87990467d [HTB]: Lindent |
758 |
} stk[TC_HTB_MAXDEPTH], *sp = stk; |
c9364636d htb: refactor str... |
759 760 761 762 |
BUG_ON(!hprio->row.rb_node); sp->root = hprio->row.rb_node; sp->pptr = &hprio->ptr; sp->pid = &hprio->last_ptr_id; |
1da177e4c Linux-2.6.12-rc2 |
763 764 |
for (i = 0; i < 65535; i++) { |
87990467d [HTB]: Lindent |
765 |
if (!*sp->pptr && *sp->pid) { |
10297b993 [NET] SCHED: Fix ... |
766 |
/* ptr was invalidated but id is valid - try to recover |
cc7ec456f net_sched: cleanups |
767 768 |
* the original or next ptr */ |
87990467d [HTB]: Lindent |
769 770 |
*sp->pptr = htb_id_find_next_upper(prio, sp->root, *sp->pid); |
1da177e4c Linux-2.6.12-rc2 |
771 |
} |
87990467d [HTB]: Lindent |
772 |
*sp->pid = 0; /* ptr is valid now so that remove this hint as it |
cc7ec456f net_sched: cleanups |
773 774 |
* can become out of date quickly */ |
87990467d [HTB]: Lindent |
775 |
if (!*sp->pptr) { /* we are at right end; rewind & go up */ |
1da177e4c Linux-2.6.12-rc2 |
776 |
*sp->pptr = sp->root; |
87990467d [HTB]: Lindent |
777 |
while ((*sp->pptr)->rb_left) |
1da177e4c Linux-2.6.12-rc2 |
778 779 780 |
*sp->pptr = (*sp->pptr)->rb_left; if (sp > stk) { sp--; |
512bb43eb pkt_sched: sch_ht... |
781 782 |
if (!*sp->pptr) { WARN_ON(1); |
87990467d [HTB]: Lindent |
783 |
return NULL; |
512bb43eb pkt_sched: sch_ht... |
784 |
} |
87990467d [HTB]: Lindent |
785 |
htb_next_rb_node(sp->pptr); |
1da177e4c Linux-2.6.12-rc2 |
786 787 788 |
} } else { struct htb_class *cl; |
c9364636d htb: refactor str... |
789 |
struct htb_prio *clp; |
87990467d [HTB]: Lindent |
790 791 |
cl = rb_entry(*sp->pptr, struct htb_class, node[prio]); if (!cl->level) |
1da177e4c Linux-2.6.12-rc2 |
792 |
return cl; |
c9364636d htb: refactor str... |
793 794 795 796 |
clp = &cl->un.inner.clprio[prio]; (++sp)->root = clp->feed.rb_node; sp->pptr = &clp->ptr; sp->pid = &clp->last_ptr_id; |
1da177e4c Linux-2.6.12-rc2 |
797 798 |
} } |
547b792ca net: convert BUG_... |
799 |
WARN_ON(1); |
1da177e4c Linux-2.6.12-rc2 |
800 801 802 803 |
return NULL; } /* dequeues packet at given priority and level; call only if |
cc7ec456f net_sched: cleanups |
804 805 |
* you are sure that there is active class at prio/level */ |
c9364636d htb: refactor str... |
806 807 |
static struct sk_buff *htb_dequeue_tree(struct htb_sched *q, const int prio, const int level) |
1da177e4c Linux-2.6.12-rc2 |
808 809 |
{ struct sk_buff *skb = NULL; |
87990467d [HTB]: Lindent |
810 |
struct htb_class *cl, *start; |
c9364636d htb: refactor str... |
811 812 |
struct htb_level *hlevel = &q->hlevel[level]; struct htb_prio *hprio = &hlevel->hprio[prio]; |
1da177e4c Linux-2.6.12-rc2 |
813 |
/* look initial class up in the row */ |
c9364636d htb: refactor str... |
814 |
start = cl = htb_lookup_leaf(hprio, prio); |
87990467d [HTB]: Lindent |
815 |
|
1da177e4c Linux-2.6.12-rc2 |
816 817 |
do { next: |
512bb43eb pkt_sched: sch_ht... |
818 |
if (unlikely(!cl)) |
87990467d [HTB]: Lindent |
819 |
return NULL; |
1da177e4c Linux-2.6.12-rc2 |
820 821 |
/* class can be empty - it is unlikely but can be true if leaf |
cc7ec456f net_sched: cleanups |
822 823 824 825 |
* qdisc drops packets in enqueue routine or if someone used * graft operation on the leaf since last dequeue; * simply deactivate and skip such class */ |
1da177e4c Linux-2.6.12-rc2 |
826 827 |
if (unlikely(cl->un.leaf.q->q.qlen == 0)) { struct htb_class *next; |
87990467d [HTB]: Lindent |
828 |
htb_deactivate(q, cl); |
1da177e4c Linux-2.6.12-rc2 |
829 830 831 |
/* row/level might become empty */ if ((q->row_mask[level] & (1 << prio)) == 0) |
87990467d [HTB]: Lindent |
832 |
return NULL; |
1da177e4c Linux-2.6.12-rc2 |
833 |
|
c9364636d htb: refactor str... |
834 |
next = htb_lookup_leaf(hprio, prio); |
87990467d [HTB]: Lindent |
835 836 |
if (cl == start) /* fix start if we just deleted it */ |
1da177e4c Linux-2.6.12-rc2 |
837 838 839 840 |
start = next; cl = next; goto next; } |
87990467d [HTB]: Lindent |
841 842 843 |
skb = cl->un.leaf.q->dequeue(cl->un.leaf.q); if (likely(skb != NULL)) |
1da177e4c Linux-2.6.12-rc2 |
844 |
break; |
633fe66ed pkt_sched: sch_ht... |
845 |
|
b00355db3 pkt_sched: sch_hf... |
846 |
qdisc_warn_nonwc("htb", cl->un.leaf.q); |
c9364636d htb: refactor str... |
847 848 849 |
htb_next_rb_node(level ? &cl->parent->un.inner.clprio[prio].ptr: &q->hlevel[0].hprio[prio].ptr); cl = htb_lookup_leaf(hprio, prio); |
1da177e4c Linux-2.6.12-rc2 |
850 851 852 853 |
} while (cl != start); if (likely(skb != NULL)) { |
196d97f6b htb: fix two bugs |
854 |
bstats_update(&cl->bstats, skb); |
0abf77e55 net_sched: Add ac... |
855 856 |
cl->un.leaf.deficit[level] -= qdisc_pkt_len(skb); if (cl->un.leaf.deficit[level] < 0) { |
c19f7a34f pkt_sched: sch_ht... |
857 |
cl->un.leaf.deficit[level] += cl->quantum; |
c9364636d htb: refactor str... |
858 859 |
htb_next_rb_node(level ? &cl->parent->un.inner.clprio[prio].ptr : &q->hlevel[0].hprio[prio].ptr); |
1da177e4c Linux-2.6.12-rc2 |
860 861 |
} /* this used to be after charge_class but this constelation |
cc7ec456f net_sched: cleanups |
862 863 |
* gives us slightly better performance */ |
1da177e4c Linux-2.6.12-rc2 |
864 |
if (!cl->un.leaf.q->q.qlen) |
87990467d [HTB]: Lindent |
865 |
htb_deactivate(q, cl); |
c9726d689 [NET_SCHED]: Make... |
866 |
htb_charge_class(q, cl, level, skb); |
1da177e4c Linux-2.6.12-rc2 |
867 868 869 |
} return skb; } |
1da177e4c Linux-2.6.12-rc2 |
870 871 |
static struct sk_buff *htb_dequeue(struct Qdisc *sch) { |
9190b3b32 net_sched: accura... |
872 |
struct sk_buff *skb; |
1da177e4c Linux-2.6.12-rc2 |
873 874 |
struct htb_sched *q = qdisc_priv(sch); int level; |
5343a7f8b net_sched: htb: d... |
875 |
s64 next_event; |
a73be0406 pkt_sched: sch_ht... |
876 |
unsigned long start_at; |
1da177e4c Linux-2.6.12-rc2 |
877 878 |
/* try to dequeue direct packets as high prio (!) to minimize cpu work */ |
48da34b7a sched: add and us... |
879 |
skb = __qdisc_dequeue_head(&q->direct_queue); |
87990467d [HTB]: Lindent |
880 |
if (skb != NULL) { |
9190b3b32 net_sched: accura... |
881 882 |
ok: qdisc_bstats_update(sch, skb); |
431e3a8e3 sch_htb: update b... |
883 |
qdisc_qstats_backlog_dec(sch, skb); |
1da177e4c Linux-2.6.12-rc2 |
884 885 886 |
sch->q.qlen--; return skb; } |
87990467d [HTB]: Lindent |
887 888 |
if (!sch->q.qlen) goto fin; |
d2de875c6 net: use ktime_ge... |
889 |
q->now = ktime_get_ns(); |
a73be0406 pkt_sched: sch_ht... |
890 |
start_at = jiffies; |
1da177e4c Linux-2.6.12-rc2 |
891 |
|
d2fe85da5 net: sched: integ... |
892 |
next_event = q->now + 5LLU * NSEC_PER_SEC; |
633fe66ed pkt_sched: sch_ht... |
893 |
|
1da177e4c Linux-2.6.12-rc2 |
894 895 896 |
for (level = 0; level < TC_HTB_MAXDEPTH; level++) { /* common case optimization - skip event handler quickly */ int m; |
c9364636d htb: refactor str... |
897 |
s64 event = q->near_ev_cache[level]; |
fb983d457 [NET_SCHED]: sch_... |
898 |
|
c9364636d htb: refactor str... |
899 |
if (q->now >= event) { |
a73be0406 pkt_sched: sch_ht... |
900 |
event = htb_do_events(q, level, start_at); |
2e4b3b0e8 [NET_SCHED]: sch_... |
901 |
if (!event) |
56b765b79 htb: improved acc... |
902 |
event = q->now + NSEC_PER_SEC; |
2e4b3b0e8 [NET_SCHED]: sch_... |
903 |
q->near_ev_cache[level] = event; |
c9364636d htb: refactor str... |
904 |
} |
fb983d457 [NET_SCHED]: sch_... |
905 |
|
c08513471 pkt_sched: sch_ht... |
906 |
if (next_event > event) |
fb983d457 [NET_SCHED]: sch_... |
907 |
next_event = event; |
87990467d [HTB]: Lindent |
908 |
|
1da177e4c Linux-2.6.12-rc2 |
909 910 |
m = ~q->row_mask[level]; while (m != (int)(-1)) { |
87990467d [HTB]: Lindent |
911 |
int prio = ffz(m); |
cc7ec456f net_sched: cleanups |
912 |
|
1da177e4c Linux-2.6.12-rc2 |
913 |
m |= 1 << prio; |
87990467d [HTB]: Lindent |
914 |
skb = htb_dequeue_tree(q, prio, level); |
9190b3b32 net_sched: accura... |
915 916 |
if (likely(skb != NULL)) goto ok; |
1da177e4c Linux-2.6.12-rc2 |
917 918 |
} } |
25331d6ce net: sched: imple... |
919 |
qdisc_qstats_overlimit(sch); |
a9efad8b2 net_sched: avoid ... |
920 |
if (likely(next_event > q->now)) |
45f50bed1 net_sched: remove... |
921 |
qdisc_watchdog_schedule_ns(&q->watchdog, next_event); |
a9efad8b2 net_sched: avoid ... |
922 |
else |
1224736d9 pkt_sched: sch_ht... |
923 |
schedule_work(&q->work); |
1da177e4c Linux-2.6.12-rc2 |
924 |
fin: |
1da177e4c Linux-2.6.12-rc2 |
925 926 |
return skb; } |
1da177e4c Linux-2.6.12-rc2 |
927 928 |
/* reset all classes */ /* always caled under BH & queue lock */ |
87990467d [HTB]: Lindent |
929 |
static void htb_reset(struct Qdisc *sch) |
1da177e4c Linux-2.6.12-rc2 |
930 931 |
{ struct htb_sched *q = qdisc_priv(sch); |
f4c1f3e0c net-sched: sch_ht... |
932 |
struct htb_class *cl; |
f4c1f3e0c net-sched: sch_ht... |
933 |
unsigned int i; |
0cef296da [HTB]: Use hlist ... |
934 |
|
f4c1f3e0c net-sched: sch_ht... |
935 |
for (i = 0; i < q->clhash.hashsize; i++) { |
b67bfe0d4 hlist: drop the n... |
936 |
hlist_for_each_entry(cl, &q->clhash.hash[i], common.hnode) { |
1da177e4c Linux-2.6.12-rc2 |
937 |
if (cl->level) |
87990467d [HTB]: Lindent |
938 |
memset(&cl->un.inner, 0, sizeof(cl->un.inner)); |
1da177e4c Linux-2.6.12-rc2 |
939 |
else { |
87990467d [HTB]: Lindent |
940 |
if (cl->un.leaf.q) |
1da177e4c Linux-2.6.12-rc2 |
941 942 943 944 945 |
qdisc_reset(cl->un.leaf.q); INIT_LIST_HEAD(&cl->un.leaf.drop_list); } cl->prio_activity = 0; cl->cmode = HTB_CAN_SEND; |
1da177e4c Linux-2.6.12-rc2 |
946 947 |
} } |
fb983d457 [NET_SCHED]: sch_... |
948 |
qdisc_watchdog_cancel(&q->watchdog); |
a5a9f5346 net_sched: sch_ht... |
949 |
__qdisc_reset_queue(&q->direct_queue); |
1da177e4c Linux-2.6.12-rc2 |
950 |
sch->q.qlen = 0; |
431e3a8e3 sch_htb: update b... |
951 |
sch->qstats.backlog = 0; |
c9364636d htb: refactor str... |
952 |
memset(q->hlevel, 0, sizeof(q->hlevel)); |
87990467d [HTB]: Lindent |
953 |
memset(q->row_mask, 0, sizeof(q->row_mask)); |
1da177e4c Linux-2.6.12-rc2 |
954 |
for (i = 0; i < TC_HTB_NUMPRIO; i++) |
87990467d [HTB]: Lindent |
955 |
INIT_LIST_HEAD(q->drops + i); |
1da177e4c Linux-2.6.12-rc2 |
956 |
} |
27a3421e4 [NET_SCHED]: Use ... |
957 958 959 960 961 |
static const struct nla_policy htb_policy[TCA_HTB_MAX + 1] = { [TCA_HTB_PARMS] = { .len = sizeof(struct tc_htb_opt) }, [TCA_HTB_INIT] = { .len = sizeof(struct tc_htb_glob) }, [TCA_HTB_CTAB] = { .type = NLA_BINARY, .len = TC_RTAB_SIZE }, [TCA_HTB_RTAB] = { .type = NLA_BINARY, .len = TC_RTAB_SIZE }, |
6906f4ed6 htb: add HTB_DIRE... |
962 |
[TCA_HTB_DIRECT_QLEN] = { .type = NLA_U32 }, |
df62cdf34 net_sched: htb: s... |
963 964 |
[TCA_HTB_RATE64] = { .type = NLA_U64 }, [TCA_HTB_CEIL64] = { .type = NLA_U64 }, |
27a3421e4 [NET_SCHED]: Use ... |
965 |
}; |
1224736d9 pkt_sched: sch_ht... |
966 967 968 969 |
static void htb_work_func(struct work_struct *work) { struct htb_sched *q = container_of(work, struct htb_sched, work); struct Qdisc *sch = q->watchdog.qdisc; |
0ee13627f htb: call qdisc_r... |
970 |
rcu_read_lock(); |
1224736d9 pkt_sched: sch_ht... |
971 |
__netif_schedule(qdisc_root(sch)); |
0ee13627f htb: call qdisc_r... |
972 |
rcu_read_unlock(); |
1224736d9 pkt_sched: sch_ht... |
973 |
} |
1e90474c3 [NET_SCHED]: Conv... |
974 |
static int htb_init(struct Qdisc *sch, struct nlattr *opt) |
1da177e4c Linux-2.6.12-rc2 |
975 976 |
{ struct htb_sched *q = qdisc_priv(sch); |
6906f4ed6 htb: add HTB_DIRE... |
977 |
struct nlattr *tb[TCA_HTB_MAX + 1]; |
1da177e4c Linux-2.6.12-rc2 |
978 |
struct tc_htb_glob *gopt; |
cee63723b [NET_SCHED]: Prop... |
979 |
int err; |
1da177e4c Linux-2.6.12-rc2 |
980 |
int i; |
cee63723b [NET_SCHED]: Prop... |
981 982 983 |
if (!opt) return -EINVAL; |
6906f4ed6 htb: add HTB_DIRE... |
984 |
err = nla_parse_nested(tb, TCA_HTB_MAX, opt, htb_policy); |
cee63723b [NET_SCHED]: Prop... |
985 986 |
if (err < 0) return err; |
6906f4ed6 htb: add HTB_DIRE... |
987 |
if (!tb[TCA_HTB_INIT]) |
1da177e4c Linux-2.6.12-rc2 |
988 |
return -EINVAL; |
6906f4ed6 htb: add HTB_DIRE... |
989 |
|
1e90474c3 [NET_SCHED]: Conv... |
990 |
gopt = nla_data(tb[TCA_HTB_INIT]); |
6906f4ed6 htb: add HTB_DIRE... |
991 |
if (gopt->version != HTB_VER >> 16) |
1da177e4c Linux-2.6.12-rc2 |
992 |
return -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
993 |
|
f4c1f3e0c net-sched: sch_ht... |
994 995 996 |
err = qdisc_class_hash_init(&q->clhash); if (err < 0) return err; |
1da177e4c Linux-2.6.12-rc2 |
997 |
for (i = 0; i < TC_HTB_NUMPRIO; i++) |
87990467d [HTB]: Lindent |
998 |
INIT_LIST_HEAD(q->drops + i); |
1da177e4c Linux-2.6.12-rc2 |
999 |
|
fb983d457 [NET_SCHED]: sch_... |
1000 |
qdisc_watchdog_init(&q->watchdog, sch); |
1224736d9 pkt_sched: sch_ht... |
1001 |
INIT_WORK(&q->work, htb_work_func); |
48da34b7a sched: add and us... |
1002 |
qdisc_skb_head_init(&q->direct_queue); |
1da177e4c Linux-2.6.12-rc2 |
1003 |
|
6906f4ed6 htb: add HTB_DIRE... |
1004 1005 |
if (tb[TCA_HTB_DIRECT_QLEN]) q->direct_qlen = nla_get_u32(tb[TCA_HTB_DIRECT_QLEN]); |
348e3435c net: sched: drop ... |
1006 |
else |
6906f4ed6 htb: add HTB_DIRE... |
1007 |
q->direct_qlen = qdisc_dev(sch)->tx_queue_len; |
348e3435c net: sched: drop ... |
1008 |
|
1da177e4c Linux-2.6.12-rc2 |
1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 |
if ((q->rate2quantum = gopt->rate2quantum) < 1) q->rate2quantum = 1; q->defcls = gopt->defcls; return 0; } static int htb_dump(struct Qdisc *sch, struct sk_buff *skb) { struct htb_sched *q = qdisc_priv(sch); |
4b3550ef5 [NET_SCHED]: Use ... |
1019 |
struct nlattr *nest; |
1da177e4c Linux-2.6.12-rc2 |
1020 |
struct tc_htb_glob gopt; |
4b3550ef5 [NET_SCHED]: Use ... |
1021 |
|
6f542efcb net_sched: htb: d... |
1022 1023 1024 |
/* Its safe to not acquire qdisc lock. As we hold RTNL, * no change can happen on the qdisc parameters. */ |
1da177e4c Linux-2.6.12-rc2 |
1025 |
|
4b3550ef5 [NET_SCHED]: Use ... |
1026 |
gopt.direct_pkts = q->direct_pkts; |
1da177e4c Linux-2.6.12-rc2 |
1027 1028 1029 |
gopt.version = HTB_VER; gopt.rate2quantum = q->rate2quantum; gopt.defcls = q->defcls; |
3bf72957d [HTB]: Remove bro... |
1030 |
gopt.debug = 0; |
4b3550ef5 [NET_SCHED]: Use ... |
1031 1032 1033 1034 |
nest = nla_nest_start(skb, TCA_OPTIONS); if (nest == NULL) goto nla_put_failure; |
6906f4ed6 htb: add HTB_DIRE... |
1035 1036 |
if (nla_put(skb, TCA_HTB_INIT, sizeof(gopt), &gopt) || nla_put_u32(skb, TCA_HTB_DIRECT_QLEN, q->direct_qlen)) |
1b34ec43c pkt_sched: Stop u... |
1037 |
goto nla_put_failure; |
4b3550ef5 [NET_SCHED]: Use ... |
1038 |
|
6f542efcb net_sched: htb: d... |
1039 |
return nla_nest_end(skb, nest); |
4b3550ef5 [NET_SCHED]: Use ... |
1040 |
|
1e90474c3 [NET_SCHED]: Conv... |
1041 |
nla_put_failure: |
4b3550ef5 [NET_SCHED]: Use ... |
1042 |
nla_nest_cancel(skb, nest); |
1da177e4c Linux-2.6.12-rc2 |
1043 1044 1045 1046 |
return -1; } static int htb_dump_class(struct Qdisc *sch, unsigned long arg, |
87990467d [HTB]: Lindent |
1047 |
struct sk_buff *skb, struct tcmsg *tcm) |
1da177e4c Linux-2.6.12-rc2 |
1048 |
{ |
87990467d [HTB]: Lindent |
1049 |
struct htb_class *cl = (struct htb_class *)arg; |
4b3550ef5 [NET_SCHED]: Use ... |
1050 |
struct nlattr *nest; |
1da177e4c Linux-2.6.12-rc2 |
1051 |
struct tc_htb_opt opt; |
6f542efcb net_sched: htb: d... |
1052 1053 1054 |
/* Its safe to not acquire qdisc lock. As we hold RTNL, * no change can happen on the class parameters. */ |
f4c1f3e0c net-sched: sch_ht... |
1055 1056 |
tcm->tcm_parent = cl->parent ? cl->parent->common.classid : TC_H_ROOT; tcm->tcm_handle = cl->common.classid; |
1da177e4c Linux-2.6.12-rc2 |
1057 1058 |
if (!cl->level && cl->un.leaf.q) tcm->tcm_info = cl->un.leaf.q->handle; |
4b3550ef5 [NET_SCHED]: Use ... |
1059 1060 1061 |
nest = nla_nest_start(skb, TCA_OPTIONS); if (nest == NULL) goto nla_put_failure; |
1da177e4c Linux-2.6.12-rc2 |
1062 |
|
87990467d [HTB]: Lindent |
1063 |
memset(&opt, 0, sizeof(opt)); |
1da177e4c Linux-2.6.12-rc2 |
1064 |
|
01cb71d2d net_sched: restor... |
1065 |
psched_ratecfg_getrate(&opt.rate, &cl->rate); |
9c10f4115 htb: fix values i... |
1066 |
opt.buffer = PSCHED_NS2TICKS(cl->buffer); |
01cb71d2d net_sched: restor... |
1067 |
psched_ratecfg_getrate(&opt.ceil, &cl->ceil); |
9c10f4115 htb: fix values i... |
1068 |
opt.cbuffer = PSCHED_NS2TICKS(cl->cbuffer); |
c19f7a34f pkt_sched: sch_ht... |
1069 1070 |
opt.quantum = cl->quantum; opt.prio = cl->prio; |
87990467d [HTB]: Lindent |
1071 |
opt.level = cl->level; |
1b34ec43c pkt_sched: Stop u... |
1072 1073 |
if (nla_put(skb, TCA_HTB_PARMS, sizeof(opt), &opt)) goto nla_put_failure; |
df62cdf34 net_sched: htb: s... |
1074 |
if ((cl->rate.rate_bytes_ps >= (1ULL << 32)) && |
2a51c1e8e sched: use nla_pu... |
1075 1076 |
nla_put_u64_64bit(skb, TCA_HTB_RATE64, cl->rate.rate_bytes_ps, TCA_HTB_PAD)) |
df62cdf34 net_sched: htb: s... |
1077 1078 |
goto nla_put_failure; if ((cl->ceil.rate_bytes_ps >= (1ULL << 32)) && |
2a51c1e8e sched: use nla_pu... |
1079 1080 |
nla_put_u64_64bit(skb, TCA_HTB_CEIL64, cl->ceil.rate_bytes_ps, TCA_HTB_PAD)) |
df62cdf34 net_sched: htb: s... |
1081 |
goto nla_put_failure; |
4b3550ef5 [NET_SCHED]: Use ... |
1082 |
|
6f542efcb net_sched: htb: d... |
1083 |
return nla_nest_end(skb, nest); |
4b3550ef5 [NET_SCHED]: Use ... |
1084 |
|
1e90474c3 [NET_SCHED]: Conv... |
1085 |
nla_put_failure: |
4b3550ef5 [NET_SCHED]: Use ... |
1086 |
nla_nest_cancel(skb, nest); |
1da177e4c Linux-2.6.12-rc2 |
1087 1088 1089 1090 |
return -1; } static int |
87990467d [HTB]: Lindent |
1091 |
htb_dump_class_stats(struct Qdisc *sch, unsigned long arg, struct gnet_dump *d) |
1da177e4c Linux-2.6.12-rc2 |
1092 |
{ |
87990467d [HTB]: Lindent |
1093 |
struct htb_class *cl = (struct htb_class *)arg; |
338ed9b4d net_sched: sch_ht... |
1094 1095 1096 |
struct gnet_stats_queue qs = { .drops = cl->drops, }; |
640158536 net: sched: restr... |
1097 |
__u32 qlen = 0; |
1da177e4c Linux-2.6.12-rc2 |
1098 |
|
338ed9b4d net_sched: sch_ht... |
1099 |
if (!cl->level && cl->un.leaf.q) { |
640158536 net: sched: restr... |
1100 |
qlen = cl->un.leaf.q->q.qlen; |
338ed9b4d net_sched: sch_ht... |
1101 1102 |
qs.backlog = cl->un.leaf.q->qstats.backlog; } |
0564bf0af net/sched/sch_htb... |
1103 1104 1105 1106 |
cl->xstats.tokens = clamp_t(s64, PSCHED_NS2TICKS(cl->tokens), INT_MIN, INT_MAX); cl->xstats.ctokens = clamp_t(s64, PSCHED_NS2TICKS(cl->ctokens), INT_MIN, INT_MAX); |
1da177e4c Linux-2.6.12-rc2 |
1107 |
|
edb09eb17 net: sched: do no... |
1108 1109 |
if (gnet_stats_copy_basic(qdisc_root_sleeping_running(sch), d, NULL, &cl->bstats) < 0 || |
d250a5f90 pkt_sched: gen_es... |
1110 |
gnet_stats_copy_rate_est(d, NULL, &cl->rate_est) < 0 || |
338ed9b4d net_sched: sch_ht... |
1111 |
gnet_stats_copy_queue(d, NULL, &qs, qlen) < 0) |
1da177e4c Linux-2.6.12-rc2 |
1112 1113 1114 1115 1116 1117 |
return -1; return gnet_stats_copy_app(d, &cl->xstats, sizeof(cl->xstats)); } static int htb_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, |
87990467d [HTB]: Lindent |
1118 |
struct Qdisc **old) |
1da177e4c Linux-2.6.12-rc2 |
1119 |
{ |
87990467d [HTB]: Lindent |
1120 |
struct htb_class *cl = (struct htb_class *)arg; |
1da177e4c Linux-2.6.12-rc2 |
1121 |
|
5b9a9ccfa net_sched: remove... |
1122 1123 1124 |
if (cl->level) return -EINVAL; if (new == NULL && |
3511c9132 net_sched: remove... |
1125 |
(new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, |
5b9a9ccfa net_sched: remove... |
1126 1127 |
cl->common.classid)) == NULL) return -ENOBUFS; |
86a7996cc net_sched: introd... |
1128 |
*old = qdisc_replace(sch, new, &cl->un.leaf.q); |
5b9a9ccfa net_sched: remove... |
1129 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
1130 |
} |
87990467d [HTB]: Lindent |
1131 |
static struct Qdisc *htb_leaf(struct Qdisc *sch, unsigned long arg) |
1da177e4c Linux-2.6.12-rc2 |
1132 |
{ |
87990467d [HTB]: Lindent |
1133 |
struct htb_class *cl = (struct htb_class *)arg; |
5b9a9ccfa net_sched: remove... |
1134 |
return !cl->level ? cl->un.leaf.q : NULL; |
1da177e4c Linux-2.6.12-rc2 |
1135 |
} |
256d61b87 [NET_SCHED]: Fix ... |
1136 1137 1138 1139 1140 1141 1142 |
static void htb_qlen_notify(struct Qdisc *sch, unsigned long arg) { struct htb_class *cl = (struct htb_class *)arg; if (cl->un.leaf.q->q.qlen == 0) htb_deactivate(qdisc_priv(sch), cl); } |
1da177e4c Linux-2.6.12-rc2 |
1143 1144 |
static unsigned long htb_get(struct Qdisc *sch, u32 classid) { |
87990467d [HTB]: Lindent |
1145 1146 |
struct htb_class *cl = htb_find(classid, sch); if (cl) |
1da177e4c Linux-2.6.12-rc2 |
1147 1148 1149 |
cl->refcnt++; return (unsigned long)cl; } |
160d5e10f [NET_SCHED] sch_h... |
1150 1151 1152 1153 1154 |
static inline int htb_parent_last_child(struct htb_class *cl) { if (!cl->parent) /* the root class */ return 0; |
420775993 net-sched: sch_ht... |
1155 |
if (cl->parent->children > 1) |
160d5e10f [NET_SCHED] sch_h... |
1156 1157 |
/* not the last child */ return 0; |
160d5e10f [NET_SCHED] sch_h... |
1158 1159 |
return 1; } |
3ba08b00e sch_htb: remove f... |
1160 1161 |
static void htb_parent_to_leaf(struct htb_sched *q, struct htb_class *cl, struct Qdisc *new_q) |
160d5e10f [NET_SCHED] sch_h... |
1162 1163 |
{ struct htb_class *parent = cl->parent; |
547b792ca net: convert BUG_... |
1164 |
WARN_ON(cl->level || !cl->un.leaf.q || cl->prio_activity); |
160d5e10f [NET_SCHED] sch_h... |
1165 |
|
3ba08b00e sch_htb: remove f... |
1166 |
if (parent->cmode != HTB_CAN_SEND) |
c9364636d htb: refactor str... |
1167 1168 |
htb_safe_rb_erase(&parent->pq_node, &q->hlevel[parent->level].wait_pq); |
3ba08b00e sch_htb: remove f... |
1169 |
|
160d5e10f [NET_SCHED] sch_h... |
1170 1171 1172 1173 |
parent->level = 0; memset(&parent->un.inner, 0, sizeof(parent->un.inner)); INIT_LIST_HEAD(&parent->un.leaf.drop_list); parent->un.leaf.q = new_q ? new_q : &noop_qdisc; |
160d5e10f [NET_SCHED] sch_h... |
1174 1175 |
parent->tokens = parent->buffer; parent->ctokens = parent->cbuffer; |
d2de875c6 net: use ktime_ge... |
1176 |
parent->t_c = ktime_get_ns(); |
160d5e10f [NET_SCHED] sch_h... |
1177 1178 |
parent->cmode = HTB_CAN_SEND; } |
87990467d [HTB]: Lindent |
1179 |
static void htb_destroy_class(struct Qdisc *sch, struct htb_class *cl) |
1da177e4c Linux-2.6.12-rc2 |
1180 |
{ |
1da177e4c Linux-2.6.12-rc2 |
1181 |
if (!cl->level) { |
547b792ca net: convert BUG_... |
1182 |
WARN_ON(!cl->un.leaf.q); |
1da177e4c Linux-2.6.12-rc2 |
1183 1184 |
qdisc_destroy(cl->un.leaf.q); } |
ee39e10c2 [NET_SCHED]: sch_... |
1185 |
gen_kill_estimator(&cl->bstats, &cl->rate_est); |
ff31ab56c net-sched: change... |
1186 |
tcf_destroy_chain(&cl->filter_list); |
1da177e4c Linux-2.6.12-rc2 |
1187 1188 |
kfree(cl); } |
87990467d [HTB]: Lindent |
1189 |
static void htb_destroy(struct Qdisc *sch) |
1da177e4c Linux-2.6.12-rc2 |
1190 1191 |
{ struct htb_sched *q = qdisc_priv(sch); |
b67bfe0d4 hlist: drop the n... |
1192 |
struct hlist_node *next; |
fbd8f1379 net-sched: sch_ht... |
1193 1194 |
struct htb_class *cl; unsigned int i; |
1da177e4c Linux-2.6.12-rc2 |
1195 |
|
1224736d9 pkt_sched: sch_ht... |
1196 |
cancel_work_sync(&q->work); |
fb983d457 [NET_SCHED]: sch_... |
1197 |
qdisc_watchdog_cancel(&q->watchdog); |
1da177e4c Linux-2.6.12-rc2 |
1198 |
/* This line used to be after htb_destroy_class call below |
cc7ec456f net_sched: cleanups |
1199 1200 1201 1202 |
* and surprisingly it worked in 2.4. But it must precede it * because filter need its target class alive to be able to call * unbind_filter on it (without Oops). */ |
ff31ab56c net-sched: change... |
1203 |
tcf_destroy_chain(&q->filter_list); |
87990467d [HTB]: Lindent |
1204 |
|
f4c1f3e0c net-sched: sch_ht... |
1205 |
for (i = 0; i < q->clhash.hashsize; i++) { |
b67bfe0d4 hlist: drop the n... |
1206 |
hlist_for_each_entry(cl, &q->clhash.hash[i], common.hnode) |
fbd8f1379 net-sched: sch_ht... |
1207 1208 |
tcf_destroy_chain(&cl->filter_list); } |
f4c1f3e0c net-sched: sch_ht... |
1209 |
for (i = 0; i < q->clhash.hashsize; i++) { |
b67bfe0d4 hlist: drop the n... |
1210 |
hlist_for_each_entry_safe(cl, next, &q->clhash.hash[i], |
f4c1f3e0c net-sched: sch_ht... |
1211 |
common.hnode) |
fbd8f1379 net-sched: sch_ht... |
1212 1213 |
htb_destroy_class(sch, cl); } |
f4c1f3e0c net-sched: sch_ht... |
1214 |
qdisc_class_hash_destroy(&q->clhash); |
a5a9f5346 net_sched: sch_ht... |
1215 |
__qdisc_reset_queue(&q->direct_queue); |
1da177e4c Linux-2.6.12-rc2 |
1216 1217 1218 1219 1220 |
} static int htb_delete(struct Qdisc *sch, unsigned long arg) { struct htb_sched *q = qdisc_priv(sch); |
87990467d [HTB]: Lindent |
1221 |
struct htb_class *cl = (struct htb_class *)arg; |
160d5e10f [NET_SCHED] sch_h... |
1222 1223 |
struct Qdisc *new_q = NULL; int last_child = 0; |
1da177e4c Linux-2.6.12-rc2 |
1224 |
|
a071d2724 sch_htb: use /* c... |
1225 1226 1227 1228 |
/* TODO: why don't allow to delete subtree ? references ? does * tc subsys guarantee us that in htb_destroy it holds no class * refs so that we can remove children safely there ? */ |
420775993 net-sched: sch_ht... |
1229 |
if (cl->children || cl->filter_cnt) |
1da177e4c Linux-2.6.12-rc2 |
1230 |
return -EBUSY; |
87990467d [HTB]: Lindent |
1231 |
|
160d5e10f [NET_SCHED] sch_h... |
1232 |
if (!cl->level && htb_parent_last_child(cl)) { |
3511c9132 net_sched: remove... |
1233 |
new_q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, |
bb949fbd1 netdev: Create ne... |
1234 |
cl->parent->common.classid); |
160d5e10f [NET_SCHED] sch_h... |
1235 1236 |
last_child = 1; } |
1da177e4c Linux-2.6.12-rc2 |
1237 |
sch_tree_lock(sch); |
87990467d [HTB]: Lindent |
1238 |
|
814a175e7 [NET_SCHED]: sch_... |
1239 |
if (!cl->level) { |
2ccccf5fb net_sched: update... |
1240 1241 |
unsigned int qlen = cl->un.leaf.q->q.qlen; unsigned int backlog = cl->un.leaf.q->qstats.backlog; |
814a175e7 [NET_SCHED]: sch_... |
1242 |
qdisc_reset(cl->un.leaf.q); |
2ccccf5fb net_sched: update... |
1243 |
qdisc_tree_reduce_backlog(cl->un.leaf.q, qlen, backlog); |
814a175e7 [NET_SCHED]: sch_... |
1244 |
} |
f4c1f3e0c net-sched: sch_ht... |
1245 1246 |
/* delete from hash and active; remainder in destroy_class */ qdisc_class_hash_remove(&q->clhash, &cl->common); |
26b284de5 pkt_sched: Fix oo... |
1247 1248 |
if (cl->parent) cl->parent->children--; |
c38c83cb7 [NET_SCHED]: sch_... |
1249 |
|
1da177e4c Linux-2.6.12-rc2 |
1250 |
if (cl->prio_activity) |
87990467d [HTB]: Lindent |
1251 |
htb_deactivate(q, cl); |
1da177e4c Linux-2.6.12-rc2 |
1252 |
|
fbd8f1379 net-sched: sch_ht... |
1253 |
if (cl->cmode != HTB_CAN_SEND) |
c9364636d htb: refactor str... |
1254 1255 |
htb_safe_rb_erase(&cl->pq_node, &q->hlevel[cl->level].wait_pq); |
fbd8f1379 net-sched: sch_ht... |
1256 |
|
160d5e10f [NET_SCHED] sch_h... |
1257 |
if (last_child) |
3ba08b00e sch_htb: remove f... |
1258 |
htb_parent_to_leaf(q, cl, new_q); |
160d5e10f [NET_SCHED] sch_h... |
1259 |
|
7cd0a6387 pkt_sched: Change... |
1260 1261 1262 1263 1264 |
BUG_ON(--cl->refcnt == 0); /* * This shouldn't happen: we "hold" one cops->get() when called * from tc_ctl_tclass; the destroy method is done from cops->put(). */ |
1da177e4c Linux-2.6.12-rc2 |
1265 1266 1267 1268 1269 1270 1271 |
sch_tree_unlock(sch); return 0; } static void htb_put(struct Qdisc *sch, unsigned long arg) { |
87990467d [HTB]: Lindent |
1272 |
struct htb_class *cl = (struct htb_class *)arg; |
1da177e4c Linux-2.6.12-rc2 |
1273 1274 |
if (--cl->refcnt == 0) |
87990467d [HTB]: Lindent |
1275 |
htb_destroy_class(sch, cl); |
1da177e4c Linux-2.6.12-rc2 |
1276 |
} |
87990467d [HTB]: Lindent |
1277 |
static int htb_change_class(struct Qdisc *sch, u32 classid, |
1e90474c3 [NET_SCHED]: Conv... |
1278 |
u32 parentid, struct nlattr **tca, |
87990467d [HTB]: Lindent |
1279 |
unsigned long *arg) |
1da177e4c Linux-2.6.12-rc2 |
1280 1281 1282 |
{ int err = -EINVAL; struct htb_sched *q = qdisc_priv(sch); |
87990467d [HTB]: Lindent |
1283 |
struct htb_class *cl = (struct htb_class *)*arg, *parent; |
1e90474c3 [NET_SCHED]: Conv... |
1284 |
struct nlattr *opt = tca[TCA_OPTIONS]; |
6906f4ed6 htb: add HTB_DIRE... |
1285 |
struct nlattr *tb[TCA_HTB_MAX + 1]; |
1da177e4c Linux-2.6.12-rc2 |
1286 |
struct tc_htb_opt *hopt; |
df62cdf34 net_sched: htb: s... |
1287 |
u64 rate64, ceil64; |
1da177e4c Linux-2.6.12-rc2 |
1288 1289 |
/* extract all subattrs from opt attr */ |
cee63723b [NET_SCHED]: Prop... |
1290 1291 |
if (!opt) goto failure; |
e18434c45 net_sched: use __... |
1292 |
err = nla_parse_nested(tb, TCA_HTB_MAX, opt, htb_policy); |
cee63723b [NET_SCHED]: Prop... |
1293 1294 1295 1296 |
if (err < 0) goto failure; err = -EINVAL; |
27a3421e4 [NET_SCHED]: Use ... |
1297 |
if (tb[TCA_HTB_PARMS] == NULL) |
1da177e4c Linux-2.6.12-rc2 |
1298 |
goto failure; |
1da177e4c Linux-2.6.12-rc2 |
1299 |
|
87990467d [HTB]: Lindent |
1300 |
parent = parentid == TC_H_ROOT ? NULL : htb_find(parentid, sch); |
1e90474c3 [NET_SCHED]: Conv... |
1301 |
hopt = nla_data(tb[TCA_HTB_PARMS]); |
196d97f6b htb: fix two bugs |
1302 |
if (!hopt->rate.rate || !hopt->ceil.rate) |
87990467d [HTB]: Lindent |
1303 |
goto failure; |
1da177e4c Linux-2.6.12-rc2 |
1304 |
|
8a8e3d84b net_sched: restor... |
1305 |
/* Keeping backward compatible with rate_table based iproute2 tc */ |
6b1dd8560 sch_htb: remove u... |
1306 1307 1308 1309 1310 |
if (hopt->rate.linklayer == TC_LINKLAYER_UNAWARE) qdisc_put_rtab(qdisc_get_rtab(&hopt->rate, tb[TCA_HTB_RTAB])); if (hopt->ceil.linklayer == TC_LINKLAYER_UNAWARE) qdisc_put_rtab(qdisc_get_rtab(&hopt->ceil, tb[TCA_HTB_CTAB])); |
8a8e3d84b net_sched: restor... |
1311 |
|
87990467d [HTB]: Lindent |
1312 |
if (!cl) { /* new class */ |
1da177e4c Linux-2.6.12-rc2 |
1313 |
struct Qdisc *new_q; |
3696f625e [HTB]: rbtree cle... |
1314 |
int prio; |
ee39e10c2 [NET_SCHED]: sch_... |
1315 |
struct { |
1e90474c3 [NET_SCHED]: Conv... |
1316 |
struct nlattr nla; |
ee39e10c2 [NET_SCHED]: sch_... |
1317 1318 |
struct gnet_estimator opt; } est = { |
1e90474c3 [NET_SCHED]: Conv... |
1319 1320 1321 |
.nla = { .nla_len = nla_attr_size(sizeof(est.opt)), .nla_type = TCA_RATE, |
ee39e10c2 [NET_SCHED]: sch_... |
1322 1323 1324 1325 1326 1327 1328 |
}, .opt = { /* 4s interval, 16s averaging constant */ .interval = 2, .ewma_log = 2, }, }; |
3696f625e [HTB]: rbtree cle... |
1329 |
|
1da177e4c Linux-2.6.12-rc2 |
1330 |
/* check for valid classid */ |
f64f9e719 net: Move && and ... |
1331 1332 |
if (!classid || TC_H_MAJ(classid ^ sch->handle) || htb_find(classid, sch)) |
1da177e4c Linux-2.6.12-rc2 |
1333 1334 1335 1336 |
goto failure; /* check maximal depth */ if (parent && parent->parent && parent->parent->level < 2) { |
cc7ec456f net_sched: cleanups |
1337 1338 |
pr_err("htb: tree is too deep "); |
1da177e4c Linux-2.6.12-rc2 |
1339 1340 1341 |
goto failure; } err = -ENOBUFS; |
cc7ec456f net_sched: cleanups |
1342 1343 |
cl = kzalloc(sizeof(*cl), GFP_KERNEL); if (!cl) |
1da177e4c Linux-2.6.12-rc2 |
1344 |
goto failure; |
87990467d [HTB]: Lindent |
1345 |
|
64153ce0a net_sched: htb: d... |
1346 |
if (htb_rate_est || tca[TCA_RATE]) { |
22e0f8b93 net: sched: make ... |
1347 1348 |
err = gen_new_estimator(&cl->bstats, NULL, &cl->rate_est, |
edb09eb17 net: sched: do no... |
1349 1350 |
NULL, qdisc_root_sleeping_running(sch), |
64153ce0a net_sched: htb: d... |
1351 1352 1353 1354 1355 |
tca[TCA_RATE] ? : &est.nla); if (err) { kfree(cl); goto failure; } |
71bcb09a5 tc: check for err... |
1356 |
} |
1da177e4c Linux-2.6.12-rc2 |
1357 |
cl->refcnt = 1; |
420775993 net-sched: sch_ht... |
1358 |
cl->children = 0; |
1da177e4c Linux-2.6.12-rc2 |
1359 |
INIT_LIST_HEAD(&cl->un.leaf.drop_list); |
3696f625e [HTB]: rbtree cle... |
1360 1361 1362 1363 |
RB_CLEAR_NODE(&cl->pq_node); for (prio = 0; prio < TC_HTB_NUMPRIO; prio++) RB_CLEAR_NODE(&cl->node[prio]); |
1da177e4c Linux-2.6.12-rc2 |
1364 1365 |
/* create leaf qdisc early because it uses kmalloc(GFP_KERNEL) |
cc7ec456f net_sched: cleanups |
1366 1367 1368 |
* so that can't be used inside of sch_tree_lock * -- thanks to Karlis Peisenieks */ |
3511c9132 net_sched: remove... |
1369 |
new_q = qdisc_create_dflt(sch->dev_queue, |
bb949fbd1 netdev: Create ne... |
1370 |
&pfifo_qdisc_ops, classid); |
1da177e4c Linux-2.6.12-rc2 |
1371 1372 |
sch_tree_lock(sch); if (parent && !parent->level) { |
256d61b87 [NET_SCHED]: Fix ... |
1373 |
unsigned int qlen = parent->un.leaf.q->q.qlen; |
2ccccf5fb net_sched: update... |
1374 |
unsigned int backlog = parent->un.leaf.q->qstats.backlog; |
256d61b87 [NET_SCHED]: Fix ... |
1375 |
|
1da177e4c Linux-2.6.12-rc2 |
1376 |
/* turn parent into inner node */ |
256d61b87 [NET_SCHED]: Fix ... |
1377 |
qdisc_reset(parent->un.leaf.q); |
2ccccf5fb net_sched: update... |
1378 |
qdisc_tree_reduce_backlog(parent->un.leaf.q, qlen, backlog); |
87990467d [HTB]: Lindent |
1379 1380 1381 |
qdisc_destroy(parent->un.leaf.q); if (parent->prio_activity) htb_deactivate(q, parent); |
1da177e4c Linux-2.6.12-rc2 |
1382 1383 1384 |
/* remove from evt list because of level change */ if (parent->cmode != HTB_CAN_SEND) { |
c9364636d htb: refactor str... |
1385 |
htb_safe_rb_erase(&parent->pq_node, &q->hlevel[0].wait_pq); |
1da177e4c Linux-2.6.12-rc2 |
1386 1387 1388 |
parent->cmode = HTB_CAN_SEND; } parent->level = (parent->parent ? parent->parent->level |
87990467d [HTB]: Lindent |
1389 1390 |
: TC_HTB_MAXDEPTH) - 1; memset(&parent->un.inner, 0, sizeof(parent->un.inner)); |
1da177e4c Linux-2.6.12-rc2 |
1391 1392 1393 |
} /* leaf (we) needs elementary qdisc */ cl->un.leaf.q = new_q ? new_q : &noop_qdisc; |
f4c1f3e0c net-sched: sch_ht... |
1394 |
cl->common.classid = classid; |
87990467d [HTB]: Lindent |
1395 |
cl->parent = parent; |
1da177e4c Linux-2.6.12-rc2 |
1396 1397 |
/* set class to be in HTB_CAN_SEND state */ |
b9a7afdef htb: initialize c... |
1398 1399 |
cl->tokens = PSCHED_TICKS2NS(hopt->buffer); cl->ctokens = PSCHED_TICKS2NS(hopt->cbuffer); |
5343a7f8b net_sched: htb: d... |
1400 |
cl->mbuffer = 60ULL * NSEC_PER_SEC; /* 1min */ |
d2de875c6 net: use ktime_ge... |
1401 |
cl->t_c = ktime_get_ns(); |
1da177e4c Linux-2.6.12-rc2 |
1402 1403 1404 |
cl->cmode = HTB_CAN_SEND; /* attach to the hash list and parent's family */ |
f4c1f3e0c net-sched: sch_ht... |
1405 |
qdisc_class_hash_insert(&q->clhash, &cl->common); |
420775993 net-sched: sch_ht... |
1406 1407 |
if (parent) parent->children++; |
ee39e10c2 [NET_SCHED]: sch_... |
1408 |
} else { |
71bcb09a5 tc: check for err... |
1409 |
if (tca[TCA_RATE]) { |
22e0f8b93 net: sched: make ... |
1410 1411 |
err = gen_replace_estimator(&cl->bstats, NULL, &cl->rate_est, |
edb09eb17 net: sched: do no... |
1412 1413 |
NULL, qdisc_root_sleeping_running(sch), |
71bcb09a5 tc: check for err... |
1414 1415 1416 1417 |
tca[TCA_RATE]); if (err) return err; } |
87990467d [HTB]: Lindent |
1418 |
sch_tree_lock(sch); |
ee39e10c2 [NET_SCHED]: sch_... |
1419 |
} |
1da177e4c Linux-2.6.12-rc2 |
1420 |
|
1598f7cb4 net: sched: htb: ... |
1421 1422 1423 1424 1425 1426 |
rate64 = tb[TCA_HTB_RATE64] ? nla_get_u64(tb[TCA_HTB_RATE64]) : 0; ceil64 = tb[TCA_HTB_CEIL64] ? nla_get_u64(tb[TCA_HTB_CEIL64]) : 0; psched_ratecfg_precompute(&cl->rate, &hopt->rate, rate64); psched_ratecfg_precompute(&cl->ceil, &hopt->ceil, ceil64); |
1da177e4c Linux-2.6.12-rc2 |
1427 |
/* it used to be a nasty bug here, we have to check that node |
cc7ec456f net_sched: cleanups |
1428 1429 |
* is really leaf before changing cl->un.leaf ! */ |
1da177e4c Linux-2.6.12-rc2 |
1430 |
if (!cl->level) { |
1598f7cb4 net: sched: htb: ... |
1431 1432 1433 1434 |
u64 quantum = cl->rate.rate_bytes_ps; do_div(quantum, q->rate2quantum); cl->quantum = min_t(u64, quantum, INT_MAX); |
c19f7a34f pkt_sched: sch_ht... |
1435 |
if (!hopt->quantum && cl->quantum < 1000) { |
c17988a90 net_sched: replac... |
1436 1437 1438 |
pr_warn("HTB: quantum of class %X is small. Consider r2q change. ", cl->common.classid); |
c19f7a34f pkt_sched: sch_ht... |
1439 |
cl->quantum = 1000; |
1da177e4c Linux-2.6.12-rc2 |
1440 |
} |
c19f7a34f pkt_sched: sch_ht... |
1441 |
if (!hopt->quantum && cl->quantum > 200000) { |
c17988a90 net_sched: replac... |
1442 1443 1444 |
pr_warn("HTB: quantum of class %X is big. Consider r2q change. ", cl->common.classid); |
c19f7a34f pkt_sched: sch_ht... |
1445 |
cl->quantum = 200000; |
1da177e4c Linux-2.6.12-rc2 |
1446 1447 |
} if (hopt->quantum) |
c19f7a34f pkt_sched: sch_ht... |
1448 1449 1450 |
cl->quantum = hopt->quantum; if ((cl->prio = hopt->prio) >= TC_HTB_NUMPRIO) cl->prio = TC_HTB_NUMPRIO - 1; |
1da177e4c Linux-2.6.12-rc2 |
1451 |
} |
324f5aa52 htb: use PSCHED_T... |
1452 |
cl->buffer = PSCHED_TICKS2NS(hopt->buffer); |
f3ad857e3 net_sched: htb: f... |
1453 |
cl->cbuffer = PSCHED_TICKS2NS(hopt->cbuffer); |
56b765b79 htb: improved acc... |
1454 |
|
1da177e4c Linux-2.6.12-rc2 |
1455 |
sch_tree_unlock(sch); |
f4c1f3e0c net-sched: sch_ht... |
1456 |
qdisc_class_hash_grow(sch, &q->clhash); |
1da177e4c Linux-2.6.12-rc2 |
1457 1458 1459 1460 |
*arg = (unsigned long)cl; return 0; failure: |
1da177e4c Linux-2.6.12-rc2 |
1461 1462 |
return err; } |
25d8c0d55 net: rcu-ify tcf_... |
1463 1464 |
static struct tcf_proto __rcu **htb_find_tcf(struct Qdisc *sch, unsigned long arg) |
1da177e4c Linux-2.6.12-rc2 |
1465 1466 1467 |
{ struct htb_sched *q = qdisc_priv(sch); struct htb_class *cl = (struct htb_class *)arg; |
25d8c0d55 net: rcu-ify tcf_... |
1468 |
struct tcf_proto __rcu **fl = cl ? &cl->filter_list : &q->filter_list; |
3bf72957d [HTB]: Remove bro... |
1469 |
|
1da177e4c Linux-2.6.12-rc2 |
1470 1471 1472 1473 |
return fl; } static unsigned long htb_bind_filter(struct Qdisc *sch, unsigned long parent, |
87990467d [HTB]: Lindent |
1474 |
u32 classid) |
1da177e4c Linux-2.6.12-rc2 |
1475 |
{ |
87990467d [HTB]: Lindent |
1476 |
struct htb_class *cl = htb_find(classid, sch); |
3bf72957d [HTB]: Remove bro... |
1477 |
|
1da177e4c Linux-2.6.12-rc2 |
1478 |
/*if (cl && !cl->level) return 0; |
cc7ec456f net_sched: cleanups |
1479 1480 1481 1482 1483 1484 1485 |
* The line above used to be there to prevent attaching filters to * leaves. But at least tc_index filter uses this just to get class * for other reasons so that we have to allow for it. * ---- * 19.6.2002 As Werner explained it is ok - bind filter is just * another way to "lock" the class - unlike "get" this lock can * be broken by class during destroy IIUC. |
1da177e4c Linux-2.6.12-rc2 |
1486 |
*/ |
87990467d [HTB]: Lindent |
1487 1488 |
if (cl) cl->filter_cnt++; |
1da177e4c Linux-2.6.12-rc2 |
1489 1490 1491 1492 1493 |
return (unsigned long)cl; } static void htb_unbind_filter(struct Qdisc *sch, unsigned long arg) { |
1da177e4c Linux-2.6.12-rc2 |
1494 |
struct htb_class *cl = (struct htb_class *)arg; |
3bf72957d [HTB]: Remove bro... |
1495 |
|
87990467d [HTB]: Lindent |
1496 1497 |
if (cl) cl->filter_cnt--; |
1da177e4c Linux-2.6.12-rc2 |
1498 1499 1500 1501 1502 |
} static void htb_walk(struct Qdisc *sch, struct qdisc_walker *arg) { struct htb_sched *q = qdisc_priv(sch); |
f4c1f3e0c net-sched: sch_ht... |
1503 |
struct htb_class *cl; |
f4c1f3e0c net-sched: sch_ht... |
1504 |
unsigned int i; |
1da177e4c Linux-2.6.12-rc2 |
1505 1506 1507 |
if (arg->stop) return; |
f4c1f3e0c net-sched: sch_ht... |
1508 |
for (i = 0; i < q->clhash.hashsize; i++) { |
b67bfe0d4 hlist: drop the n... |
1509 |
hlist_for_each_entry(cl, &q->clhash.hash[i], common.hnode) { |
1da177e4c Linux-2.6.12-rc2 |
1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 |
if (arg->count < arg->skip) { arg->count++; continue; } if (arg->fn(sch, (unsigned long)cl, arg) < 0) { arg->stop = 1; return; } arg->count++; } } } |
20fea08b5 [NET]: Move Qdisc... |
1522 |
static const struct Qdisc_class_ops htb_class_ops = { |
1da177e4c Linux-2.6.12-rc2 |
1523 1524 |
.graft = htb_graft, .leaf = htb_leaf, |
256d61b87 [NET_SCHED]: Fix ... |
1525 |
.qlen_notify = htb_qlen_notify, |
1da177e4c Linux-2.6.12-rc2 |
1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 |
.get = htb_get, .put = htb_put, .change = htb_change_class, .delete = htb_delete, .walk = htb_walk, .tcf_chain = htb_find_tcf, .bind_tcf = htb_bind_filter, .unbind_tcf = htb_unbind_filter, .dump = htb_dump_class, .dump_stats = htb_dump_class_stats, }; |
20fea08b5 [NET]: Move Qdisc... |
1537 |
static struct Qdisc_ops htb_qdisc_ops __read_mostly = { |
1da177e4c Linux-2.6.12-rc2 |
1538 1539 1540 1541 1542 |
.cl_ops = &htb_class_ops, .id = "htb", .priv_size = sizeof(struct htb_sched), .enqueue = htb_enqueue, .dequeue = htb_dequeue, |
77be155cb pkt_sched: Add pe... |
1543 |
.peek = qdisc_peek_dequeued, |
1da177e4c Linux-2.6.12-rc2 |
1544 1545 1546 |
.init = htb_init, .reset = htb_reset, .destroy = htb_destroy, |
1da177e4c Linux-2.6.12-rc2 |
1547 1548 1549 1550 1551 1552 |
.dump = htb_dump, .owner = THIS_MODULE, }; static int __init htb_module_init(void) { |
87990467d [HTB]: Lindent |
1553 |
return register_qdisc(&htb_qdisc_ops); |
1da177e4c Linux-2.6.12-rc2 |
1554 |
} |
87990467d [HTB]: Lindent |
1555 |
static void __exit htb_module_exit(void) |
1da177e4c Linux-2.6.12-rc2 |
1556 |
{ |
87990467d [HTB]: Lindent |
1557 |
unregister_qdisc(&htb_qdisc_ops); |
1da177e4c Linux-2.6.12-rc2 |
1558 |
} |
87990467d [HTB]: Lindent |
1559 |
|
1da177e4c Linux-2.6.12-rc2 |
1560 1561 1562 |
module_init(htb_module_init) module_exit(htb_module_exit) MODULE_LICENSE("GPL"); |