aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/generic-2.6/patches-2.6.30
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2009-07-12 00:01:22 +0000
committerFelix Fietkau <nbd@openwrt.org>2009-07-12 00:01:22 +0000
commitd680184c26e82580ab6a870ac10af4434affdb57 (patch)
tree138017fb7cffd711f79807bcc11ebb4b3797eef9 /target/linux/generic-2.6/patches-2.6.30
parent8addc868459bba88235068615ec38f67f1e703f4 (diff)
downloadupstream-d680184c26e82580ab6a870ac10af4434affdb57.tar.gz
upstream-d680184c26e82580ab6a870ac10af4434affdb57.tar.bz2
upstream-d680184c26e82580ab6a870ac10af4434affdb57.zip
sched: allow user space to create pfifo_fast qdiscs on virtual interfaces, allow pfifo_fast qdiscs to have filters and filter actions - useful for controlling packet classification into wme classes
SVN-Revision: 16791
Diffstat (limited to 'target/linux/generic-2.6/patches-2.6.30')
-rw-r--r--target/linux/generic-2.6/patches-2.6.30/260-extend_pfifo_fast.patch142
1 files changed, 142 insertions, 0 deletions
diff --git a/target/linux/generic-2.6/patches-2.6.30/260-extend_pfifo_fast.patch b/target/linux/generic-2.6/patches-2.6.30/260-extend_pfifo_fast.patch
new file mode 100644
index 0000000000..70718e7526
--- /dev/null
+++ b/target/linux/generic-2.6/patches-2.6.30/260-extend_pfifo_fast.patch
@@ -0,0 +1,142 @@
+--- a/net/sched/sch_generic.c
++++ b/net/sched/sch_generic.c
+@@ -371,16 +371,50 @@ static const u8 prio2band[TC_PRIO_MAX+1]
+
+ #define PFIFO_FAST_BANDS 3
+
++struct pfifo_fast_sched_data {
++ struct tcf_proto *filter_list;
++ struct sk_buff_head list[PFIFO_FAST_BANDS];
++};
++
+ static inline struct sk_buff_head *prio2list(struct sk_buff *skb,
+ struct Qdisc *qdisc)
+ {
+- struct sk_buff_head *list = qdisc_priv(qdisc);
++ struct pfifo_fast_sched_data *q = qdisc_priv(qdisc);
++ struct sk_buff_head *list = q->list;
+ return list + prio2band[skb->priority & TC_PRIO_MAX];
+ }
+
++static int pfifo_fast_filter(struct sk_buff *skb, struct Qdisc* qdisc)
++{
++#ifdef CONFIG_NET_CLS_ACT
++ struct pfifo_fast_sched_data *q = qdisc_priv(qdisc);
++ int result = 0, ret = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN;
++ struct tcf_result res;
++
++ if (q->filter_list != NULL)
++ result = tc_classify(skb, q->filter_list, &res);
++ if (result >= 0) {
++ switch (result) {
++ case TC_ACT_STOLEN:
++ case TC_ACT_QUEUED:
++ ret = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN;
++ case TC_ACT_SHOT:
++ kfree_skb(skb);
++ return ret;
++ }
++ }
++#endif
++ return 0;
++}
++
+ static int pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc* qdisc)
+ {
+ struct sk_buff_head *list = prio2list(skb, qdisc);
++ int ret;
++
++ ret = pfifo_fast_filter(skb, qdisc);
++ if (ret)
++ return ret;
+
+ if (skb_queue_len(list) < qdisc_dev(qdisc)->tx_queue_len) {
+ qdisc->q.qlen++;
+@@ -392,8 +426,9 @@ static int pfifo_fast_enqueue(struct sk_
+
+ static struct sk_buff *pfifo_fast_dequeue(struct Qdisc* qdisc)
+ {
++ struct pfifo_fast_sched_data *q = qdisc_priv(qdisc);
++ struct sk_buff_head *list = q->list;
+ int prio;
+- struct sk_buff_head *list = qdisc_priv(qdisc);
+
+ for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) {
+ if (!skb_queue_empty(list + prio)) {
+@@ -420,8 +455,9 @@ static struct sk_buff *pfifo_fast_peek(s
+
+ static void pfifo_fast_reset(struct Qdisc* qdisc)
+ {
++ struct pfifo_fast_sched_data *q = qdisc_priv(qdisc);
++ struct sk_buff_head *list = q->list;
+ int prio;
+- struct sk_buff_head *list = qdisc_priv(qdisc);
+
+ for (prio = 0; prio < PFIFO_FAST_BANDS; prio++)
+ __qdisc_reset_queue(qdisc, list + prio);
+@@ -444,8 +480,9 @@ nla_put_failure:
+
+ static int pfifo_fast_init(struct Qdisc *qdisc, struct nlattr *opt)
+ {
++ struct pfifo_fast_sched_data *q = qdisc_priv(qdisc);
++ struct sk_buff_head *list = q->list;
+ int prio;
+- struct sk_buff_head *list = qdisc_priv(qdisc);
+
+ for (prio = 0; prio < PFIFO_FAST_BANDS; prio++)
+ skb_queue_head_init(list + prio);
+@@ -453,9 +490,36 @@ static int pfifo_fast_init(struct Qdisc
+ return 0;
+ }
+
++static int pfifo_fast_change_class(struct Qdisc *qdisc, u32 classid, u32 parentid,
++ struct nlattr **tca, unsigned long *arg)
++{
++ return -EOPNOTSUPP;
++}
++
++static unsigned long pfifo_fast_get(struct Qdisc *qdisc, u32 classid)
++{
++ return 0;
++}
++
++static struct tcf_proto **pfifo_fast_find_tcf(struct Qdisc *qdisc, unsigned long cl)
++{
++ struct pfifo_fast_sched_data *q = qdisc_priv(qdisc);
++
++ if (cl)
++ return NULL;
++ return &q->filter_list;
++}
++
++static const struct Qdisc_class_ops pfifo_fast_class_ops = {
++ .get = pfifo_fast_get,
++ .change = pfifo_fast_change_class,
++ .tcf_chain = pfifo_fast_find_tcf,
++};
++
+ static struct Qdisc_ops pfifo_fast_ops __read_mostly = {
+ .id = "pfifo_fast",
+- .priv_size = PFIFO_FAST_BANDS * sizeof(struct sk_buff_head),
++ .cl_ops = &pfifo_fast_class_ops,
++ .priv_size = sizeof(struct pfifo_fast_sched_data),
+ .enqueue = pfifo_fast_enqueue,
+ .dequeue = pfifo_fast_dequeue,
+ .peek = pfifo_fast_peek,
+@@ -735,3 +799,16 @@ void dev_shutdown(struct net_device *dev
+ shutdown_scheduler_queue(dev, &dev->rx_queue, &noop_qdisc);
+ WARN_ON(timer_pending(&dev->watchdog_timer));
+ }
++
++static int __init sch_generic_init(void)
++{
++ return register_qdisc(&pfifo_fast_ops);
++}
++
++static void __exit sch_generic_exit(void)
++{
++ unregister_qdisc(&pfifo_fast_ops);
++}
++
++module_init(sch_generic_init)
++module_exit(sch_generic_exit)