sched: allow user space to create pfifo_fast qdiscs on virtual interfaces, allow...
authorFelix Fietkau <nbd@openwrt.org>
Sun, 12 Jul 2009 00:01:22 +0000 (00:01 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Sun, 12 Jul 2009 00:01:22 +0000 (00:01 +0000)
SVN-Revision: 16791

package/iproute2/patches/100-allow_pfifo_fast.patch [new file with mode: 0644]
target/linux/generic-2.6/patches-2.6.28/260-extend_pfifo_fast.patch [new file with mode: 0644]
target/linux/generic-2.6/patches-2.6.30/260-extend_pfifo_fast.patch [new file with mode: 0644]

diff --git a/package/iproute2/patches/100-allow_pfifo_fast.patch b/package/iproute2/patches/100-allow_pfifo_fast.patch
new file mode 100644 (file)
index 0000000..d6c15ae
--- /dev/null
@@ -0,0 +1,9 @@
+--- a/tc/q_fifo.c
++++ b/tc/q_fifo.c
+@@ -94,5 +94,6 @@ struct qdisc_util pfifo_qdisc_util = {
+ extern int prio_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt);
+ struct qdisc_util pfifo_fast_qdisc_util = {
+       .id = "pfifo_fast",
++      .parse_qopt = fifo_parse_opt,
+       .print_qopt = prio_print_opt,
+ };
diff --git a/target/linux/generic-2.6/patches-2.6.28/260-extend_pfifo_fast.patch b/target/linux/generic-2.6/patches-2.6.28/260-extend_pfifo_fast.patch
new file mode 100644 (file)
index 0000000..a9bdb06
--- /dev/null
@@ -0,0 +1,142 @@
+--- a/net/sched/sch_generic.c
++++ b/net/sched/sch_generic.c
+@@ -382,16 +382,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++;
+@@ -403,8 +437,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)) {
+@@ -424,8 +459,9 @@ static int pfifo_fast_requeue(struct sk_
+ 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);
+@@ -448,8 +484,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);
+@@ -457,9 +494,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,
+       .requeue        =       pfifo_fast_requeue,
+@@ -739,3 +803,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)
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 (file)
index 0000000..70718e7
--- /dev/null
@@ -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)