aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/sch_htb.c
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2008-07-06 02:22:35 -0400
committerDavid S. Miller <davem@davemloft.net>2008-07-06 02:22:35 -0400
commitf4c1f3e0c59be0e6566d9c00b1d8b204ffb861a2 (patch)
tree6dffffa3a06bf252fd23c681b19063693174bdb8 /net/sched/sch_htb.c
parentfbd8f1379aeeb3e44a59302a6b2850636130bb2a (diff)
net-sched: sch_htb: use dynamic class hash helpers
Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sched/sch_htb.c')
-rw-r--r--net/sched/sch_htb.c100
1 files changed, 42 insertions, 58 deletions
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index d01fe3a1a623..e7461a17d71e 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -51,7 +51,6 @@
51 one less than their parent. 51 one less than their parent.
52*/ 52*/
53 53
54#define HTB_HSIZE 16 /* classid hash size */
55static int htb_hysteresis __read_mostly = 0; /* whether to use mode hysteresis for speedup */ 54static int htb_hysteresis __read_mostly = 0; /* whether to use mode hysteresis for speedup */
56#define HTB_VER 0x30011 /* major must be matched with number suplied by TC as version */ 55#define HTB_VER 0x30011 /* major must be matched with number suplied by TC as version */
57 56
@@ -72,8 +71,8 @@ enum htb_cmode {
72 71
73/* interior & leaf nodes; props specific to leaves are marked L: */ 72/* interior & leaf nodes; props specific to leaves are marked L: */
74struct htb_class { 73struct htb_class {
74 struct Qdisc_class_common common;
75 /* general class parameters */ 75 /* general class parameters */
76 u32 classid;
77 struct gnet_stats_basic bstats; 76 struct gnet_stats_basic bstats;
78 struct gnet_stats_queue qstats; 77 struct gnet_stats_queue qstats;
79 struct gnet_stats_rate_est rate_est; 78 struct gnet_stats_rate_est rate_est;
@@ -83,7 +82,6 @@ struct htb_class {
83 /* topology */ 82 /* topology */
84 int level; /* our level (see above) */ 83 int level; /* our level (see above) */
85 struct htb_class *parent; /* parent class */ 84 struct htb_class *parent; /* parent class */
86 struct hlist_node hlist; /* classid hash list item */
87 struct list_head sibling; /* sibling list item */ 85 struct list_head sibling; /* sibling list item */
88 struct list_head children; /* children list */ 86 struct list_head children; /* children list */
89 87
@@ -141,7 +139,7 @@ static inline long L2T(struct htb_class *cl, struct qdisc_rate_table *rate,
141 139
142struct htb_sched { 140struct htb_sched {
143 struct list_head root; /* root classes list */ 141 struct list_head root; /* root classes list */
144 struct hlist_head hash[HTB_HSIZE]; /* hashed by classid */ 142 struct Qdisc_class_hash clhash;
145 struct list_head drops[TC_HTB_NUMPRIO];/* active leaves (for drops) */ 143 struct list_head drops[TC_HTB_NUMPRIO];/* active leaves (for drops) */
146 144
147 /* self list - roots of self generating tree */ 145 /* self list - roots of self generating tree */
@@ -176,32 +174,16 @@ struct htb_sched {
176 long direct_pkts; 174 long direct_pkts;
177}; 175};
178 176
179/* compute hash of size HTB_HSIZE for given handle */
180static inline int htb_hash(u32 h)
181{
182#if HTB_HSIZE != 16
183#error "Declare new hash for your HTB_HSIZE"
184#endif
185 h ^= h >> 8; /* stolen from cbq_hash */
186 h ^= h >> 4;
187 return h & 0xf;
188}
189
190/* find class in global hash table using given handle */ 177/* find class in global hash table using given handle */
191static inline struct htb_class *htb_find(u32 handle, struct Qdisc *sch) 178static inline struct htb_class *htb_find(u32 handle, struct Qdisc *sch)
192{ 179{
193 struct htb_sched *q = qdisc_priv(sch); 180 struct htb_sched *q = qdisc_priv(sch);
194 struct hlist_node *p; 181 struct Qdisc_class_common *clc;
195 struct htb_class *cl;
196 182
197 if (TC_H_MAJ(handle) != sch->handle) 183 clc = qdisc_class_find(&q->clhash, handle);
184 if (clc == NULL)
198 return NULL; 185 return NULL;
199 186 return container_of(clc, struct htb_class, common);
200 hlist_for_each_entry(cl, p, q->hash + htb_hash(handle), hlist) {
201 if (cl->classid == handle)
202 return cl;
203 }
204 return NULL;
205} 187}
206 188
207/** 189/**
@@ -282,7 +264,7 @@ static void htb_add_to_id_tree(struct rb_root *root,
282 parent = *p; 264 parent = *p;
283 c = rb_entry(parent, struct htb_class, node[prio]); 265 c = rb_entry(parent, struct htb_class, node[prio]);
284 266
285 if (cl->classid > c->classid) 267 if (cl->common.classid > c->common.classid)
286 p = &parent->rb_right; 268 p = &parent->rb_right;
287 else 269 else
288 p = &parent->rb_left; 270 p = &parent->rb_left;
@@ -446,7 +428,7 @@ static void htb_deactivate_prios(struct htb_sched *q, struct htb_class *cl)
446 /* we are removing child which is pointed to from 428 /* we are removing child which is pointed to from
447 parent feed - forget the pointer but remember 429 parent feed - forget the pointer but remember
448 classid */ 430 classid */
449 p->un.inner.last_ptr_id[prio] = cl->classid; 431 p->un.inner.last_ptr_id[prio] = cl->common.classid;
450 p->un.inner.ptr[prio] = NULL; 432 p->un.inner.ptr[prio] = NULL;
451 } 433 }
452 434
@@ -751,10 +733,10 @@ static struct rb_node *htb_id_find_next_upper(int prio, struct rb_node *n,
751 while (n) { 733 while (n) {
752 struct htb_class *cl = 734 struct htb_class *cl =
753 rb_entry(n, struct htb_class, node[prio]); 735 rb_entry(n, struct htb_class, node[prio]);
754 if (id == cl->classid) 736 if (id == cl->common.classid)
755 return n; 737 return n;
756 738
757 if (id > cl->classid) { 739 if (id > cl->common.classid) {
758 n = n->rb_right; 740 n = n->rb_right;
759 } else { 741 } else {
760 r = n; 742 r = n;
@@ -864,7 +846,7 @@ next:
864 if (!cl->warned) { 846 if (!cl->warned) {
865 printk(KERN_WARNING 847 printk(KERN_WARNING
866 "htb: class %X isn't work conserving ?!\n", 848 "htb: class %X isn't work conserving ?!\n",
867 cl->classid); 849 cl->common.classid);
868 cl->warned = 1; 850 cl->warned = 1;
869 } 851 }
870 q->nwc_hit++; 852 q->nwc_hit++;
@@ -975,13 +957,12 @@ static unsigned int htb_drop(struct Qdisc *sch)
975static void htb_reset(struct Qdisc *sch) 957static void htb_reset(struct Qdisc *sch)
976{ 958{
977 struct htb_sched *q = qdisc_priv(sch); 959 struct htb_sched *q = qdisc_priv(sch);
978 int i; 960 struct htb_class *cl;
979 961 struct hlist_node *n;
980 for (i = 0; i < HTB_HSIZE; i++) { 962 unsigned int i;
981 struct hlist_node *p;
982 struct htb_class *cl;
983 963
984 hlist_for_each_entry(cl, p, q->hash + i, hlist) { 964 for (i = 0; i < q->clhash.hashsize; i++) {
965 hlist_for_each_entry(cl, n, &q->clhash.hash[i], common.hnode) {
985 if (cl->level) 966 if (cl->level)
986 memset(&cl->un.inner, 0, sizeof(cl->un.inner)); 967 memset(&cl->un.inner, 0, sizeof(cl->un.inner));
987 else { 968 else {
@@ -1040,8 +1021,9 @@ static int htb_init(struct Qdisc *sch, struct nlattr *opt)
1040 } 1021 }
1041 1022
1042 INIT_LIST_HEAD(&q->root); 1023 INIT_LIST_HEAD(&q->root);
1043 for (i = 0; i < HTB_HSIZE; i++) 1024 err = qdisc_class_hash_init(&q->clhash);
1044 INIT_HLIST_HEAD(q->hash + i); 1025 if (err < 0)
1026 return err;
1045 for (i = 0; i < TC_HTB_NUMPRIO; i++) 1027 for (i = 0; i < TC_HTB_NUMPRIO; i++)
1046 INIT_LIST_HEAD(q->drops + i); 1028 INIT_LIST_HEAD(q->drops + i);
1047 1029
@@ -1096,8 +1078,8 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg,
1096 struct tc_htb_opt opt; 1078 struct tc_htb_opt opt;
1097 1079
1098 spin_lock_bh(&sch->dev->queue_lock); 1080 spin_lock_bh(&sch->dev->queue_lock);
1099 tcm->tcm_parent = cl->parent ? cl->parent->classid : TC_H_ROOT; 1081 tcm->tcm_parent = cl->parent ? cl->parent->common.classid : TC_H_ROOT;
1100 tcm->tcm_handle = cl->classid; 1082 tcm->tcm_handle = cl->common.classid;
1101 if (!cl->level && cl->un.leaf.q) 1083 if (!cl->level && cl->un.leaf.q)
1102 tcm->tcm_info = cl->un.leaf.q->handle; 1084 tcm->tcm_info = cl->un.leaf.q->handle;
1103 1085
@@ -1152,7 +1134,7 @@ static int htb_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
1152 if (cl && !cl->level) { 1134 if (cl && !cl->level) {
1153 if (new == NULL && 1135 if (new == NULL &&
1154 (new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, 1136 (new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops,
1155 cl->classid)) 1137 cl->common.classid))
1156 == NULL) 1138 == NULL)
1157 return -ENOBUFS; 1139 return -ENOBUFS;
1158 sch_tree_lock(sch); 1140 sch_tree_lock(sch);
@@ -1253,14 +1235,16 @@ static void htb_destroy(struct Qdisc *sch)
1253 unbind_filter on it (without Oops). */ 1235 unbind_filter on it (without Oops). */
1254 tcf_destroy_chain(&q->filter_list); 1236 tcf_destroy_chain(&q->filter_list);
1255 1237
1256 for (i = 0; i < HTB_HSIZE; i++) { 1238 for (i = 0; i < q->clhash.hashsize; i++) {
1257 hlist_for_each_entry(cl, n, q->hash + i, hlist) 1239 hlist_for_each_entry(cl, n, &q->clhash.hash[i], common.hnode)
1258 tcf_destroy_chain(&cl->filter_list); 1240 tcf_destroy_chain(&cl->filter_list);
1259 } 1241 }
1260 for (i = 0; i < HTB_HSIZE; i++) { 1242 for (i = 0; i < q->clhash.hashsize; i++) {
1261 hlist_for_each_entry_safe(cl, n, next, q->hash + i, hlist) 1243 hlist_for_each_entry_safe(cl, n, next, &q->clhash.hash[i],
1244 common.hnode)
1262 htb_destroy_class(sch, cl); 1245 htb_destroy_class(sch, cl);
1263 } 1246 }
1247 qdisc_class_hash_destroy(&q->clhash);
1264 __skb_queue_purge(&q->direct_queue); 1248 __skb_queue_purge(&q->direct_queue);
1265} 1249}
1266 1250
@@ -1280,7 +1264,7 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg)
1280 1264
1281 if (!cl->level && htb_parent_last_child(cl)) { 1265 if (!cl->level && htb_parent_last_child(cl)) {
1282 new_q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, 1266 new_q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops,
1283 cl->parent->classid); 1267 cl->parent->common.classid);
1284 last_child = 1; 1268 last_child = 1;
1285 } 1269 }
1286 1270
@@ -1292,8 +1276,8 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg)
1292 qdisc_tree_decrease_qlen(cl->un.leaf.q, qlen); 1276 qdisc_tree_decrease_qlen(cl->un.leaf.q, qlen);
1293 } 1277 }
1294 1278
1295 /* delete from hash, sibling list and active */ 1279 /* delete from hash and active; remainder in destroy_class */
1296 hlist_del(&cl->hlist); 1280 qdisc_class_hash_remove(&q->clhash, &cl->common);
1297 list_del(&cl->sibling); 1281 list_del(&cl->sibling);
1298 1282
1299 if (cl->prio_activity) 1283 if (cl->prio_activity)
@@ -1390,7 +1374,6 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
1390 tca[TCA_RATE] ? : &est.nla); 1374 tca[TCA_RATE] ? : &est.nla);
1391 cl->refcnt = 1; 1375 cl->refcnt = 1;
1392 INIT_LIST_HEAD(&cl->sibling); 1376 INIT_LIST_HEAD(&cl->sibling);
1393 INIT_HLIST_NODE(&cl->hlist);
1394 INIT_LIST_HEAD(&cl->children); 1377 INIT_LIST_HEAD(&cl->children);
1395 INIT_LIST_HEAD(&cl->un.leaf.drop_list); 1378 INIT_LIST_HEAD(&cl->un.leaf.drop_list);
1396 RB_CLEAR_NODE(&cl->pq_node); 1379 RB_CLEAR_NODE(&cl->pq_node);
@@ -1425,7 +1408,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
1425 /* leaf (we) needs elementary qdisc */ 1408 /* leaf (we) needs elementary qdisc */
1426 cl->un.leaf.q = new_q ? new_q : &noop_qdisc; 1409 cl->un.leaf.q = new_q ? new_q : &noop_qdisc;
1427 1410
1428 cl->classid = classid; 1411 cl->common.classid = classid;
1429 cl->parent = parent; 1412 cl->parent = parent;
1430 1413
1431 /* set class to be in HTB_CAN_SEND state */ 1414 /* set class to be in HTB_CAN_SEND state */
@@ -1436,7 +1419,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
1436 cl->cmode = HTB_CAN_SEND; 1419 cl->cmode = HTB_CAN_SEND;
1437 1420
1438 /* attach to the hash list and parent's family */ 1421 /* attach to the hash list and parent's family */
1439 hlist_add_head(&cl->hlist, q->hash + htb_hash(classid)); 1422 qdisc_class_hash_insert(&q->clhash, &cl->common);
1440 list_add_tail(&cl->sibling, 1423 list_add_tail(&cl->sibling,
1441 parent ? &parent->children : &q->root); 1424 parent ? &parent->children : &q->root);
1442 } else { 1425 } else {
@@ -1454,13 +1437,13 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
1454 if (!hopt->quantum && cl->un.leaf.quantum < 1000) { 1437 if (!hopt->quantum && cl->un.leaf.quantum < 1000) {
1455 printk(KERN_WARNING 1438 printk(KERN_WARNING
1456 "HTB: quantum of class %X is small. Consider r2q change.\n", 1439 "HTB: quantum of class %X is small. Consider r2q change.\n",
1457 cl->classid); 1440 cl->common.classid);
1458 cl->un.leaf.quantum = 1000; 1441 cl->un.leaf.quantum = 1000;
1459 } 1442 }
1460 if (!hopt->quantum && cl->un.leaf.quantum > 200000) { 1443 if (!hopt->quantum && cl->un.leaf.quantum > 200000) {
1461 printk(KERN_WARNING 1444 printk(KERN_WARNING
1462 "HTB: quantum of class %X is big. Consider r2q change.\n", 1445 "HTB: quantum of class %X is big. Consider r2q change.\n",
1463 cl->classid); 1446 cl->common.classid);
1464 cl->un.leaf.quantum = 200000; 1447 cl->un.leaf.quantum = 200000;
1465 } 1448 }
1466 if (hopt->quantum) 1449 if (hopt->quantum)
@@ -1483,6 +1466,8 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
1483 cl->ceil = ctab; 1466 cl->ceil = ctab;
1484 sch_tree_unlock(sch); 1467 sch_tree_unlock(sch);
1485 1468
1469 qdisc_class_hash_grow(sch, &q->clhash);
1470
1486 *arg = (unsigned long)cl; 1471 *arg = (unsigned long)cl;
1487 return 0; 1472 return 0;
1488 1473
@@ -1539,16 +1524,15 @@ static void htb_unbind_filter(struct Qdisc *sch, unsigned long arg)
1539static void htb_walk(struct Qdisc *sch, struct qdisc_walker *arg) 1524static void htb_walk(struct Qdisc *sch, struct qdisc_walker *arg)
1540{ 1525{
1541 struct htb_sched *q = qdisc_priv(sch); 1526 struct htb_sched *q = qdisc_priv(sch);
1542 int i; 1527 struct htb_class *cl;
1528 struct hlist_node *n;
1529 unsigned int i;
1543 1530
1544 if (arg->stop) 1531 if (arg->stop)
1545 return; 1532 return;
1546 1533
1547 for (i = 0; i < HTB_HSIZE; i++) { 1534 for (i = 0; i < q->clhash.hashsize; i++) {
1548 struct hlist_node *p; 1535 hlist_for_each_entry(cl, n, &q->clhash.hash[i], common.hnode) {
1549 struct htb_class *cl;
1550
1551 hlist_for_each_entry(cl, p, q->hash + i, hlist) {
1552 if (arg->count < arg->skip) { 1536 if (arg->count < arg->skip) {
1553 arg->count++; 1537 arg->count++;
1554 continue; 1538 continue;