| 1 | --- a/net/sched/sch_generic.c |
| 2 | +++ b/net/sched/sch_generic.c |
| 3 | @@ -371,16 +371,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 | @@ -392,8 +426,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 | @@ -420,8 +455,9 @@ static struct sk_buff *pfifo_fast_peek(s |
| 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 | @@ -444,8 +480,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 | @@ -453,9 +490,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 | .peek = pfifo_fast_peek, |
| 126 | @@ -735,3 +799,18 @@ 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 | +#ifdef CONFIG_NET_SCHED |
| 132 | +static int __init sch_generic_init(void) |
| 133 | +{ |
| 134 | + return register_qdisc(&pfifo_fast_ops); |
| 135 | +} |
| 136 | + |
| 137 | +static void __exit sch_generic_exit(void) |
| 138 | +{ |
| 139 | + unregister_qdisc(&pfifo_fast_ops); |
| 140 | +} |
| 141 | + |
| 142 | +module_init(sch_generic_init) |
| 143 | +module_exit(sch_generic_exit) |
| 144 | +#endif |
| 145 | |