1
2
3
4
5
6
7
8
9
10
11#include <linux/module.h>
12#include <linux/types.h>
13#include <linux/list.h>
14#include <linux/skbuff.h>
15#include <linux/rtnetlink.h>
16
17#include <net/netlink.h>
18#include <net/pkt_sched.h>
19#include <net/pkt_cls.h>
20
21struct ingress_sched_data {
22 struct tcf_block *block;
23 struct tcf_block_ext_info block_info;
24 struct mini_Qdisc_pair miniqp;
25};
26
27static struct Qdisc *ingress_leaf(struct Qdisc *sch, unsigned long arg)
28{
29 return NULL;
30}
31
32static unsigned long ingress_find(struct Qdisc *sch, u32 classid)
33{
34 return TC_H_MIN(classid) + 1;
35}
36
37static unsigned long ingress_bind_filter(struct Qdisc *sch,
38 unsigned long parent, u32 classid)
39{
40 return ingress_find(sch, classid);
41}
42
43static void ingress_unbind_filter(struct Qdisc *sch, unsigned long cl)
44{
45}
46
47static void ingress_walk(struct Qdisc *sch, struct qdisc_walker *walker)
48{
49}
50
51static struct tcf_block *ingress_tcf_block(struct Qdisc *sch, unsigned long cl,
52 struct netlink_ext_ack *extack)
53{
54 struct ingress_sched_data *q = qdisc_priv(sch);
55
56 return q->block;
57}
58
59static void clsact_chain_head_change(struct tcf_proto *tp_head, void *priv)
60{
61 struct mini_Qdisc_pair *miniqp = priv;
62
63 mini_qdisc_pair_swap(miniqp, tp_head);
64};
65
66static void ingress_ingress_block_set(struct Qdisc *sch, u32 block_index)
67{
68 struct ingress_sched_data *q = qdisc_priv(sch);
69
70 q->block_info.block_index = block_index;
71}
72
73static u32 ingress_ingress_block_get(struct Qdisc *sch)
74{
75 struct ingress_sched_data *q = qdisc_priv(sch);
76
77 return q->block_info.block_index;
78}
79
80static int ingress_init(struct Qdisc *sch, struct nlattr *opt,
81 struct netlink_ext_ack *extack)
82{
83 struct ingress_sched_data *q = qdisc_priv(sch);
84 struct net_device *dev = qdisc_dev(sch);
85 int err;
86
87 net_inc_ingress_queue();
88
89 mini_qdisc_pair_init(&q->miniqp, sch, &dev->miniq_ingress);
90
91 q->block_info.binder_type = FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS;
92 q->block_info.chain_head_change = clsact_chain_head_change;
93 q->block_info.chain_head_change_priv = &q->miniqp;
94
95 err = tcf_block_get_ext(&q->block, sch, &q->block_info, extack);
96 if (err)
97 return err;
98
99 mini_qdisc_pair_block_init(&q->miniqp, q->block);
100
101 return 0;
102}
103
104static void ingress_destroy(struct Qdisc *sch)
105{
106 struct ingress_sched_data *q = qdisc_priv(sch);
107
108 tcf_block_put_ext(q->block, sch, &q->block_info);
109 net_dec_ingress_queue();
110}
111
112static int ingress_dump(struct Qdisc *sch, struct sk_buff *skb)
113{
114 struct nlattr *nest;
115
116 nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
117 if (nest == NULL)
118 goto nla_put_failure;
119
120 return nla_nest_end(skb, nest);
121
122nla_put_failure:
123 nla_nest_cancel(skb, nest);
124 return -1;
125}
126
127static const struct Qdisc_class_ops ingress_class_ops = {
128 .flags = QDISC_CLASS_OPS_DOIT_UNLOCKED,
129 .leaf = ingress_leaf,
130 .find = ingress_find,
131 .walk = ingress_walk,
132 .tcf_block = ingress_tcf_block,
133 .bind_tcf = ingress_bind_filter,
134 .unbind_tcf = ingress_unbind_filter,
135};
136
137static struct Qdisc_ops ingress_qdisc_ops __read_mostly = {
138 .cl_ops = &ingress_class_ops,
139 .id = "ingress",
140 .priv_size = sizeof(struct ingress_sched_data),
141 .static_flags = TCQ_F_CPUSTATS,
142 .init = ingress_init,
143 .destroy = ingress_destroy,
144 .dump = ingress_dump,
145 .ingress_block_set = ingress_ingress_block_set,
146 .ingress_block_get = ingress_ingress_block_get,
147 .owner = THIS_MODULE,
148};
149
150struct clsact_sched_data {
151 struct tcf_block *ingress_block;
152 struct tcf_block *egress_block;
153 struct tcf_block_ext_info ingress_block_info;
154 struct tcf_block_ext_info egress_block_info;
155 struct mini_Qdisc_pair miniqp_ingress;
156 struct mini_Qdisc_pair miniqp_egress;
157};
158
159static unsigned long clsact_find(struct Qdisc *sch, u32 classid)
160{
161 switch (TC_H_MIN(classid)) {
162 case TC_H_MIN(TC_H_MIN_INGRESS):
163 case TC_H_MIN(TC_H_MIN_EGRESS):
164 return TC_H_MIN(classid);
165 default:
166 return 0;
167 }
168}
169
170static unsigned long clsact_bind_filter(struct Qdisc *sch,
171 unsigned long parent, u32 classid)
172{
173 return clsact_find(sch, classid);
174}
175
176static struct tcf_block *clsact_tcf_block(struct Qdisc *sch, unsigned long cl,
177 struct netlink_ext_ack *extack)
178{
179 struct clsact_sched_data *q = qdisc_priv(sch);
180
181 switch (cl) {
182 case TC_H_MIN(TC_H_MIN_INGRESS):
183 return q->ingress_block;
184 case TC_H_MIN(TC_H_MIN_EGRESS):
185 return q->egress_block;
186 default:
187 return NULL;
188 }
189}
190
191static void clsact_ingress_block_set(struct Qdisc *sch, u32 block_index)
192{
193 struct clsact_sched_data *q = qdisc_priv(sch);
194
195 q->ingress_block_info.block_index = block_index;
196}
197
198static void clsact_egress_block_set(struct Qdisc *sch, u32 block_index)
199{
200 struct clsact_sched_data *q = qdisc_priv(sch);
201
202 q->egress_block_info.block_index = block_index;
203}
204
205static u32 clsact_ingress_block_get(struct Qdisc *sch)
206{
207 struct clsact_sched_data *q = qdisc_priv(sch);
208
209 return q->ingress_block_info.block_index;
210}
211
212static u32 clsact_egress_block_get(struct Qdisc *sch)
213{
214 struct clsact_sched_data *q = qdisc_priv(sch);
215
216 return q->egress_block_info.block_index;
217}
218
219static int clsact_init(struct Qdisc *sch, struct nlattr *opt,
220 struct netlink_ext_ack *extack)
221{
222 struct clsact_sched_data *q = qdisc_priv(sch);
223 struct net_device *dev = qdisc_dev(sch);
224 int err;
225
226 net_inc_ingress_queue();
227 net_inc_egress_queue();
228
229 mini_qdisc_pair_init(&q->miniqp_ingress, sch, &dev->miniq_ingress);
230
231 q->ingress_block_info.binder_type = FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS;
232 q->ingress_block_info.chain_head_change = clsact_chain_head_change;
233 q->ingress_block_info.chain_head_change_priv = &q->miniqp_ingress;
234
235 err = tcf_block_get_ext(&q->ingress_block, sch, &q->ingress_block_info,
236 extack);
237 if (err)
238 return err;
239
240 mini_qdisc_pair_block_init(&q->miniqp_ingress, q->ingress_block);
241
242 mini_qdisc_pair_init(&q->miniqp_egress, sch, &dev->miniq_egress);
243
244 q->egress_block_info.binder_type = FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS;
245 q->egress_block_info.chain_head_change = clsact_chain_head_change;
246 q->egress_block_info.chain_head_change_priv = &q->miniqp_egress;
247
248 return tcf_block_get_ext(&q->egress_block, sch, &q->egress_block_info, extack);
249}
250
251static void clsact_destroy(struct Qdisc *sch)
252{
253 struct clsact_sched_data *q = qdisc_priv(sch);
254
255 tcf_block_put_ext(q->egress_block, sch, &q->egress_block_info);
256 tcf_block_put_ext(q->ingress_block, sch, &q->ingress_block_info);
257
258 net_dec_ingress_queue();
259 net_dec_egress_queue();
260}
261
262static const struct Qdisc_class_ops clsact_class_ops = {
263 .flags = QDISC_CLASS_OPS_DOIT_UNLOCKED,
264 .leaf = ingress_leaf,
265 .find = clsact_find,
266 .walk = ingress_walk,
267 .tcf_block = clsact_tcf_block,
268 .bind_tcf = clsact_bind_filter,
269 .unbind_tcf = ingress_unbind_filter,
270};
271
272static struct Qdisc_ops clsact_qdisc_ops __read_mostly = {
273 .cl_ops = &clsact_class_ops,
274 .id = "clsact",
275 .priv_size = sizeof(struct clsact_sched_data),
276 .static_flags = TCQ_F_CPUSTATS,
277 .init = clsact_init,
278 .destroy = clsact_destroy,
279 .dump = ingress_dump,
280 .ingress_block_set = clsact_ingress_block_set,
281 .egress_block_set = clsact_egress_block_set,
282 .ingress_block_get = clsact_ingress_block_get,
283 .egress_block_get = clsact_egress_block_get,
284 .owner = THIS_MODULE,
285};
286
287static int __init ingress_module_init(void)
288{
289 int ret;
290
291 ret = register_qdisc(&ingress_qdisc_ops);
292 if (!ret) {
293 ret = register_qdisc(&clsact_qdisc_ops);
294 if (ret)
295 unregister_qdisc(&ingress_qdisc_ops);
296 }
297
298 return ret;
299}
300
301static void __exit ingress_module_exit(void)
302{
303 unregister_qdisc(&ingress_qdisc_ops);
304 unregister_qdisc(&clsact_qdisc_ops);
305}
306
307module_init(ingress_module_init);
308module_exit(ingress_module_exit);
309
310MODULE_ALIAS("sch_clsact");
311MODULE_LICENSE("GPL");
312