aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/sch_prio.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched/sch_prio.c')
-rw-r--r--net/sched/sch_prio.c145
1 files changed, 114 insertions, 31 deletions
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c
index 6d7542c26e47..2d8c08493d6e 100644
--- a/net/sched/sch_prio.c
+++ b/net/sched/sch_prio.c
@@ -12,37 +12,23 @@
12 */ 12 */
13 13
14#include <linux/module.h> 14#include <linux/module.h>
15#include <asm/uaccess.h>
16#include <asm/system.h>
17#include <linux/bitops.h>
18#include <linux/types.h> 15#include <linux/types.h>
19#include <linux/kernel.h> 16#include <linux/kernel.h>
20#include <linux/string.h> 17#include <linux/string.h>
21#include <linux/mm.h>
22#include <linux/socket.h>
23#include <linux/sockios.h>
24#include <linux/in.h>
25#include <linux/errno.h> 18#include <linux/errno.h>
26#include <linux/interrupt.h>
27#include <linux/if_ether.h>
28#include <linux/inet.h>
29#include <linux/netdevice.h>
30#include <linux/etherdevice.h>
31#include <linux/notifier.h>
32#include <net/ip.h>
33#include <net/route.h>
34#include <linux/skbuff.h> 19#include <linux/skbuff.h>
35#include <net/netlink.h> 20#include <net/netlink.h>
36#include <net/sock.h>
37#include <net/pkt_sched.h> 21#include <net/pkt_sched.h>
38 22
39 23
40struct prio_sched_data 24struct prio_sched_data
41{ 25{
42 int bands; 26 int bands;
27 int curband; /* for round-robin */
43 struct tcf_proto *filter_list; 28 struct tcf_proto *filter_list;
44 u8 prio2band[TC_PRIO_MAX+1]; 29 u8 prio2band[TC_PRIO_MAX+1];
45 struct Qdisc *queues[TCQ_PRIO_BANDS]; 30 struct Qdisc *queues[TCQ_PRIO_BANDS];
31 int mq;
46}; 32};
47 33
48 34
@@ -70,14 +56,17 @@ prio_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
70#endif 56#endif
71 if (TC_H_MAJ(band)) 57 if (TC_H_MAJ(band))
72 band = 0; 58 band = 0;
73 return q->queues[q->prio2band[band&TC_PRIO_MAX]]; 59 band = q->prio2band[band&TC_PRIO_MAX];
60 goto out;
74 } 61 }
75 band = res.classid; 62 band = res.classid;
76 } 63 }
77 band = TC_H_MIN(band) - 1; 64 band = TC_H_MIN(band) - 1;
78 if (band >= q->bands) 65 if (band >= q->bands)
79 return q->queues[q->prio2band[0]]; 66 band = q->prio2band[0];
80 67out:
68 if (q->mq)
69 skb_set_queue_mapping(skb, band);
81 return q->queues[band]; 70 return q->queues[band];
82} 71}
83 72
@@ -144,17 +133,58 @@ prio_dequeue(struct Qdisc* sch)
144 struct Qdisc *qdisc; 133 struct Qdisc *qdisc;
145 134
146 for (prio = 0; prio < q->bands; prio++) { 135 for (prio = 0; prio < q->bands; prio++) {
147 qdisc = q->queues[prio]; 136 /* Check if the target subqueue is available before
148 skb = qdisc->dequeue(qdisc); 137 * pulling an skb. This way we avoid excessive requeues
149 if (skb) { 138 * for slower queues.
150 sch->q.qlen--; 139 */
151 return skb; 140 if (!netif_subqueue_stopped(sch->dev, (q->mq ? prio : 0))) {
141 qdisc = q->queues[prio];
142 skb = qdisc->dequeue(qdisc);
143 if (skb) {
144 sch->q.qlen--;
145 return skb;
146 }
152 } 147 }
153 } 148 }
154 return NULL; 149 return NULL;
155 150
156} 151}
157 152
153static struct sk_buff *rr_dequeue(struct Qdisc* sch)
154{
155 struct sk_buff *skb;
156 struct prio_sched_data *q = qdisc_priv(sch);
157 struct Qdisc *qdisc;
158 int bandcount;
159
160 /* Only take one pass through the queues. If nothing is available,
161 * return nothing.
162 */
163 for (bandcount = 0; bandcount < q->bands; bandcount++) {
164 /* Check if the target subqueue is available before
165 * pulling an skb. This way we avoid excessive requeues
166 * for slower queues. If the queue is stopped, try the
167 * next queue.
168 */
169 if (!netif_subqueue_stopped(sch->dev,
170 (q->mq ? q->curband : 0))) {
171 qdisc = q->queues[q->curband];
172 skb = qdisc->dequeue(qdisc);
173 if (skb) {
174 sch->q.qlen--;
175 q->curband++;
176 if (q->curband >= q->bands)
177 q->curband = 0;
178 return skb;
179 }
180 }
181 q->curband++;
182 if (q->curband >= q->bands)
183 q->curband = 0;
184 }
185 return NULL;
186}
187
158static unsigned int prio_drop(struct Qdisc* sch) 188static unsigned int prio_drop(struct Qdisc* sch)
159{ 189{
160 struct prio_sched_data *q = qdisc_priv(sch); 190 struct prio_sched_data *q = qdisc_priv(sch);
@@ -198,21 +228,41 @@ prio_destroy(struct Qdisc* sch)
198static int prio_tune(struct Qdisc *sch, struct rtattr *opt) 228static int prio_tune(struct Qdisc *sch, struct rtattr *opt)
199{ 229{
200 struct prio_sched_data *q = qdisc_priv(sch); 230 struct prio_sched_data *q = qdisc_priv(sch);
201 struct tc_prio_qopt *qopt = RTA_DATA(opt); 231 struct tc_prio_qopt *qopt;
232 struct rtattr *tb[TCA_PRIO_MAX];
202 int i; 233 int i;
203 234
204 if (opt->rta_len < RTA_LENGTH(sizeof(*qopt))) 235 if (rtattr_parse_nested_compat(tb, TCA_PRIO_MAX, opt, qopt,
236 sizeof(*qopt)))
205 return -EINVAL; 237 return -EINVAL;
206 if (qopt->bands > TCQ_PRIO_BANDS || qopt->bands < 2) 238 q->bands = qopt->bands;
239 /* If we're multiqueue, make sure the number of incoming bands
240 * matches the number of queues on the device we're associating with.
241 * If the number of bands requested is zero, then set q->bands to
242 * dev->egress_subqueue_count.
243 */
244 q->mq = RTA_GET_FLAG(tb[TCA_PRIO_MQ - 1]);
245 if (q->mq) {
246 if (sch->handle != TC_H_ROOT)
247 return -EINVAL;
248 if (netif_is_multiqueue(sch->dev)) {
249 if (q->bands == 0)
250 q->bands = sch->dev->egress_subqueue_count;
251 else if (q->bands != sch->dev->egress_subqueue_count)
252 return -EINVAL;
253 } else
254 return -EOPNOTSUPP;
255 }
256
257 if (q->bands > TCQ_PRIO_BANDS || q->bands < 2)
207 return -EINVAL; 258 return -EINVAL;
208 259
209 for (i=0; i<=TC_PRIO_MAX; i++) { 260 for (i=0; i<=TC_PRIO_MAX; i++) {
210 if (qopt->priomap[i] >= qopt->bands) 261 if (qopt->priomap[i] >= q->bands)
211 return -EINVAL; 262 return -EINVAL;
212 } 263 }
213 264
214 sch_tree_lock(sch); 265 sch_tree_lock(sch);
215 q->bands = qopt->bands;
216 memcpy(q->prio2band, qopt->priomap, TC_PRIO_MAX+1); 266 memcpy(q->prio2band, qopt->priomap, TC_PRIO_MAX+1);
217 267
218 for (i=q->bands; i<TCQ_PRIO_BANDS; i++) { 268 for (i=q->bands; i<TCQ_PRIO_BANDS; i++) {
@@ -268,11 +318,17 @@ static int prio_dump(struct Qdisc *sch, struct sk_buff *skb)
268{ 318{
269 struct prio_sched_data *q = qdisc_priv(sch); 319 struct prio_sched_data *q = qdisc_priv(sch);
270 unsigned char *b = skb_tail_pointer(skb); 320 unsigned char *b = skb_tail_pointer(skb);
321 struct rtattr *nest;
271 struct tc_prio_qopt opt; 322 struct tc_prio_qopt opt;
272 323
273 opt.bands = q->bands; 324 opt.bands = q->bands;
274 memcpy(&opt.priomap, q->prio2band, TC_PRIO_MAX+1); 325 memcpy(&opt.priomap, q->prio2band, TC_PRIO_MAX+1);
275 RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt); 326
327 nest = RTA_NEST_COMPAT(skb, TCA_OPTIONS, sizeof(opt), &opt);
328 if (q->mq)
329 RTA_PUT_FLAG(skb, TCA_PRIO_MQ);
330 RTA_NEST_COMPAT_END(skb, nest);
331
276 return skb->len; 332 return skb->len;
277 333
278rtattr_failure: 334rtattr_failure:
@@ -443,17 +499,44 @@ static struct Qdisc_ops prio_qdisc_ops = {
443 .owner = THIS_MODULE, 499 .owner = THIS_MODULE,
444}; 500};
445 501
502static struct Qdisc_ops rr_qdisc_ops = {
503 .next = NULL,
504 .cl_ops = &prio_class_ops,
505 .id = "rr",
506 .priv_size = sizeof(struct prio_sched_data),
507 .enqueue = prio_enqueue,
508 .dequeue = rr_dequeue,
509 .requeue = prio_requeue,
510 .drop = prio_drop,
511 .init = prio_init,
512 .reset = prio_reset,
513 .destroy = prio_destroy,
514 .change = prio_tune,
515 .dump = prio_dump,
516 .owner = THIS_MODULE,
517};
518
446static int __init prio_module_init(void) 519static int __init prio_module_init(void)
447{ 520{
448 return register_qdisc(&prio_qdisc_ops); 521 int err;
522
523 err = register_qdisc(&prio_qdisc_ops);
524 if (err < 0)
525 return err;
526 err = register_qdisc(&rr_qdisc_ops);
527 if (err < 0)
528 unregister_qdisc(&prio_qdisc_ops);
529 return err;
449} 530}
450 531
451static void __exit prio_module_exit(void) 532static void __exit prio_module_exit(void)
452{ 533{
453 unregister_qdisc(&prio_qdisc_ops); 534 unregister_qdisc(&prio_qdisc_ops);
535 unregister_qdisc(&rr_qdisc_ops);
454} 536}
455 537
456module_init(prio_module_init) 538module_init(prio_module_init)
457module_exit(prio_module_exit) 539module_exit(prio_module_exit)
458 540
459MODULE_LICENSE("GPL"); 541MODULE_LICENSE("GPL");
542MODULE_ALIAS("sch_rr");