|
|
@@ -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)
|