1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
--- 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,18 @@ void dev_shutdown(struct net_device *dev
shutdown_scheduler_queue(dev, &dev->rx_queue, &noop_qdisc);
WARN_ON(timer_pending(&dev->watchdog_timer));
}
+
+#ifdef CONFIG_NET_SCHED
+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)
+#endif
|