sched: allow user space to create pfifo_fast qdiscs on virtual interfaces, allow...
[openwrt/svn-archive/archive.git] / target / linux / generic-2.6 / patches-2.6.28 / 260-extend_pfifo_fast.patch
1 --- a/net/sched/sch_generic.c
2 +++ b/net/sched/sch_generic.c
3 @@ -382,16 +382,50 @@ static const u8 prio2band[TC_PRIO_MAX+1]
4
5 #define PFIFO_FAST_BANDS 3
6
7 +struct pfifo_fast_sched_data {
8 + struct tcf_proto *filter_list;
9 + struct sk_buff_head list[PFIFO_FAST_BANDS];
10 +};
11 +
12 static inline struct sk_buff_head *prio2list(struct sk_buff *skb,
13 struct Qdisc *qdisc)
14 {
15 - struct sk_buff_head *list = qdisc_priv(qdisc);
16 + struct pfifo_fast_sched_data *q = qdisc_priv(qdisc);
17 + struct sk_buff_head *list = q->list;
18 return list + prio2band[skb->priority & TC_PRIO_MAX];
19 }
20
21 +static int pfifo_fast_filter(struct sk_buff *skb, struct Qdisc* qdisc)
22 +{
23 +#ifdef CONFIG_NET_CLS_ACT
24 + struct pfifo_fast_sched_data *q = qdisc_priv(qdisc);
25 + int result = 0, ret = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN;
26 + struct tcf_result res;
27 +
28 + if (q->filter_list != NULL)
29 + result = tc_classify(skb, q->filter_list, &res);
30 + if (result >= 0) {
31 + switch (result) {
32 + case TC_ACT_STOLEN:
33 + case TC_ACT_QUEUED:
34 + ret = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN;
35 + case TC_ACT_SHOT:
36 + kfree_skb(skb);
37 + return ret;
38 + }
39 + }
40 +#endif
41 + return 0;
42 +}
43 +
44 static int pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc* qdisc)
45 {
46 struct sk_buff_head *list = prio2list(skb, qdisc);
47 + int ret;
48 +
49 + ret = pfifo_fast_filter(skb, qdisc);
50 + if (ret)
51 + return ret;
52
53 if (skb_queue_len(list) < qdisc_dev(qdisc)->tx_queue_len) {
54 qdisc->q.qlen++;
55 @@ -403,8 +437,9 @@ static int pfifo_fast_enqueue(struct sk_
56
57 static struct sk_buff *pfifo_fast_dequeue(struct Qdisc* qdisc)
58 {
59 + struct pfifo_fast_sched_data *q = qdisc_priv(qdisc);
60 + struct sk_buff_head *list = q->list;
61 int prio;
62 - struct sk_buff_head *list = qdisc_priv(qdisc);
63
64 for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) {
65 if (!skb_queue_empty(list + prio)) {
66 @@ -424,8 +459,9 @@ static int pfifo_fast_requeue(struct sk_
67
68 static void pfifo_fast_reset(struct Qdisc* qdisc)
69 {
70 + struct pfifo_fast_sched_data *q = qdisc_priv(qdisc);
71 + struct sk_buff_head *list = q->list;
72 int prio;
73 - struct sk_buff_head *list = qdisc_priv(qdisc);
74
75 for (prio = 0; prio < PFIFO_FAST_BANDS; prio++)
76 __qdisc_reset_queue(qdisc, list + prio);
77 @@ -448,8 +484,9 @@ nla_put_failure:
78
79 static int pfifo_fast_init(struct Qdisc *qdisc, struct nlattr *opt)
80 {
81 + struct pfifo_fast_sched_data *q = qdisc_priv(qdisc);
82 + struct sk_buff_head *list = q->list;
83 int prio;
84 - struct sk_buff_head *list = qdisc_priv(qdisc);
85
86 for (prio = 0; prio < PFIFO_FAST_BANDS; prio++)
87 skb_queue_head_init(list + prio);
88 @@ -457,9 +494,36 @@ static int pfifo_fast_init(struct Qdisc
89 return 0;
90 }
91
92 +static int pfifo_fast_change_class(struct Qdisc *qdisc, u32 classid, u32 parentid,
93 + struct nlattr **tca, unsigned long *arg)
94 +{
95 + return -EOPNOTSUPP;
96 +}
97 +
98 +static unsigned long pfifo_fast_get(struct Qdisc *qdisc, u32 classid)
99 +{
100 + return 0;
101 +}
102 +
103 +static struct tcf_proto **pfifo_fast_find_tcf(struct Qdisc *qdisc, unsigned long cl)
104 +{
105 + struct pfifo_fast_sched_data *q = qdisc_priv(qdisc);
106 +
107 + if (cl)
108 + return NULL;
109 + return &q->filter_list;
110 +}
111 +
112 +static const struct Qdisc_class_ops pfifo_fast_class_ops = {
113 + .get = pfifo_fast_get,
114 + .change = pfifo_fast_change_class,
115 + .tcf_chain = pfifo_fast_find_tcf,
116 +};
117 +
118 static struct Qdisc_ops pfifo_fast_ops __read_mostly = {
119 .id = "pfifo_fast",
120 - .priv_size = PFIFO_FAST_BANDS * sizeof(struct sk_buff_head),
121 + .cl_ops = &pfifo_fast_class_ops,
122 + .priv_size = sizeof(struct pfifo_fast_sched_data),
123 .enqueue = pfifo_fast_enqueue,
124 .dequeue = pfifo_fast_dequeue,
125 .requeue = pfifo_fast_requeue,
126 @@ -739,3 +803,16 @@ void dev_shutdown(struct net_device *dev
127 shutdown_scheduler_queue(dev, &dev->rx_queue, &noop_qdisc);
128 WARN_ON(timer_pending(&dev->watchdog_timer));
129 }
130 +
131 +static int __init sch_generic_init(void)
132 +{
133 + return register_qdisc(&pfifo_fast_ops);
134 +}
135 +
136 +static void __exit sch_generic_exit(void)
137 +{
138 + unregister_qdisc(&pfifo_fast_ops);
139 +}
140 +
141 +module_init(sch_generic_init)
142 +module_exit(sch_generic_exit)