blob: d8a9bebcab90c369bc212527638faa4c84149f50 [file] [log] [blame]
Daniel Borkmann1f211a12016-01-07 22:29:47 +01001/* net/sched/sch_ingress.c - Ingress and clsact qdisc
2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License
5 * as published by the Free Software Foundation; either version
6 * 2 of the License, or (at your option) any later version.
7 *
8 * Authors: Jamal Hadi Salim 1999
9 */
10
Linus Torvalds1da177e2005-04-16 15:20:36 -070011#include <linux/module.h>
12#include <linux/types.h>
Patrick McHardy0ba48052007-07-02 22:49:07 -070013#include <linux/list.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include <linux/skbuff.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/rtnetlink.h>
Daniel Borkmannd2788d32015-05-09 22:51:32 +020016
Arnaldo Carvalho de Melodc5fc572007-03-25 23:06:12 -070017#include <net/netlink.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <net/pkt_sched.h>
Jiri Pirkocf1facd2017-02-09 14:38:56 +010019#include <net/pkt_cls.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020
Jiri Pirko6529eab2017-05-17 11:07:55 +020021struct ingress_sched_data {
22 struct tcf_block *block;
23};
24
Linus Torvalds1da177e2005-04-16 15:20:36 -070025static struct Qdisc *ingress_leaf(struct Qdisc *sch, unsigned long arg)
26{
27 return NULL;
28}
29
Patrick McHardy58f4df42008-01-21 00:11:01 -080030static unsigned long ingress_get(struct Qdisc *sch, u32 classid)
Linus Torvalds1da177e2005-04-16 15:20:36 -070031{
Linus Torvalds1da177e2005-04-16 15:20:36 -070032 return TC_H_MIN(classid) + 1;
33}
34
Daniel Borkmann92c075d2016-06-06 22:50:39 +020035static bool ingress_cl_offload(u32 classid)
36{
37 return true;
38}
39
Linus Torvalds1da177e2005-04-16 15:20:36 -070040static unsigned long ingress_bind_filter(struct Qdisc *sch,
Patrick McHardy58f4df42008-01-21 00:11:01 -080041 unsigned long parent, u32 classid)
Linus Torvalds1da177e2005-04-16 15:20:36 -070042{
43 return ingress_get(sch, classid);
44}
45
Linus Torvalds1da177e2005-04-16 15:20:36 -070046static void ingress_put(struct Qdisc *sch, unsigned long cl)
47{
48}
49
Patrick McHardy58f4df42008-01-21 00:11:01 -080050static void ingress_walk(struct Qdisc *sch, struct qdisc_walker *walker)
Linus Torvalds1da177e2005-04-16 15:20:36 -070051{
Linus Torvalds1da177e2005-04-16 15:20:36 -070052}
53
Jiri Pirko6529eab2017-05-17 11:07:55 +020054static struct tcf_block *ingress_tcf_block(struct Qdisc *sch, unsigned long cl)
Linus Torvalds1da177e2005-04-16 15:20:36 -070055{
Jiri Pirko6529eab2017-05-17 11:07:55 +020056 struct ingress_sched_data *q = qdisc_priv(sch);
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
Jiri Pirko6529eab2017-05-17 11:07:55 +020058 return q->block;
Linus Torvalds1da177e2005-04-16 15:20:36 -070059}
60
Daniel Borkmann45771392015-04-10 23:07:54 +020061static int ingress_init(struct Qdisc *sch, struct nlattr *opt)
62{
Jiri Pirko6529eab2017-05-17 11:07:55 +020063 struct ingress_sched_data *q = qdisc_priv(sch);
64 struct net_device *dev = qdisc_dev(sch);
65 int err;
66
67 err = tcf_block_get(&q->block, &dev->ingress_cl_list);
68 if (err)
69 return err;
70
Daniel Borkmann45771392015-04-10 23:07:54 +020071 net_inc_ingress_queue();
Alexei Starovoitov087c1a62015-04-30 20:14:07 -070072 sch->flags |= TCQ_F_CPUSTATS;
Daniel Borkmann45771392015-04-10 23:07:54 +020073
74 return 0;
75}
76
Linus Torvalds1da177e2005-04-16 15:20:36 -070077static void ingress_destroy(struct Qdisc *sch)
78{
Jiri Pirko6529eab2017-05-17 11:07:55 +020079 struct ingress_sched_data *q = qdisc_priv(sch);
Linus Torvalds1da177e2005-04-16 15:20:36 -070080
Jiri Pirko6529eab2017-05-17 11:07:55 +020081 tcf_block_put(q->block);
Daniel Borkmann45771392015-04-10 23:07:54 +020082 net_dec_ingress_queue();
Linus Torvalds1da177e2005-04-16 15:20:36 -070083}
84
Linus Torvalds1da177e2005-04-16 15:20:36 -070085static int ingress_dump(struct Qdisc *sch, struct sk_buff *skb)
86{
Patrick McHardy4b3550ef2008-01-23 20:34:11 -080087 struct nlattr *nest;
Linus Torvalds1da177e2005-04-16 15:20:36 -070088
Patrick McHardy4b3550ef2008-01-23 20:34:11 -080089 nest = nla_nest_start(skb, TCA_OPTIONS);
90 if (nest == NULL)
91 goto nla_put_failure;
Daniel Borkmannd2788d32015-05-09 22:51:32 +020092
Yang Yingliangd59b7d82014-03-12 10:20:32 +080093 return nla_nest_end(skb, nest);
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
Patrick McHardy1e904742008-01-22 22:11:17 -080095nla_put_failure:
Patrick McHardy4b3550ef2008-01-23 20:34:11 -080096 nla_nest_cancel(skb, nest);
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 return -1;
98}
99
Eric Dumazet20fea082007-11-14 01:44:41 -0800100static const struct Qdisc_class_ops ingress_class_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 .leaf = ingress_leaf,
102 .get = ingress_get,
103 .put = ingress_put,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 .walk = ingress_walk,
Jiri Pirko6529eab2017-05-17 11:07:55 +0200105 .tcf_block = ingress_tcf_block,
Daniel Borkmann92c075d2016-06-06 22:50:39 +0200106 .tcf_cl_offload = ingress_cl_offload,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 .bind_tcf = ingress_bind_filter,
108 .unbind_tcf = ingress_put,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109};
110
Eric Dumazet20fea082007-11-14 01:44:41 -0800111static struct Qdisc_ops ingress_qdisc_ops __read_mostly = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 .cl_ops = &ingress_class_ops,
113 .id = "ingress",
Jiri Pirko6529eab2017-05-17 11:07:55 +0200114 .priv_size = sizeof(struct ingress_sched_data),
Daniel Borkmann45771392015-04-10 23:07:54 +0200115 .init = ingress_init,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 .destroy = ingress_destroy,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 .dump = ingress_dump,
118 .owner = THIS_MODULE,
119};
120
Jiri Pirko6529eab2017-05-17 11:07:55 +0200121struct clsact_sched_data {
122 struct tcf_block *ingress_block;
123 struct tcf_block *egress_block;
124};
125
Daniel Borkmann1f211a12016-01-07 22:29:47 +0100126static unsigned long clsact_get(struct Qdisc *sch, u32 classid)
127{
128 switch (TC_H_MIN(classid)) {
129 case TC_H_MIN(TC_H_MIN_INGRESS):
130 case TC_H_MIN(TC_H_MIN_EGRESS):
131 return TC_H_MIN(classid);
132 default:
133 return 0;
134 }
135}
136
Daniel Borkmann92c075d2016-06-06 22:50:39 +0200137static bool clsact_cl_offload(u32 classid)
138{
139 return TC_H_MIN(classid) == TC_H_MIN(TC_H_MIN_INGRESS);
140}
141
Daniel Borkmann1f211a12016-01-07 22:29:47 +0100142static unsigned long clsact_bind_filter(struct Qdisc *sch,
143 unsigned long parent, u32 classid)
144{
145 return clsact_get(sch, classid);
146}
147
Jiri Pirko6529eab2017-05-17 11:07:55 +0200148static struct tcf_block *clsact_tcf_block(struct Qdisc *sch, unsigned long cl)
Daniel Borkmann1f211a12016-01-07 22:29:47 +0100149{
Jiri Pirko6529eab2017-05-17 11:07:55 +0200150 struct clsact_sched_data *q = qdisc_priv(sch);
Daniel Borkmann1f211a12016-01-07 22:29:47 +0100151
152 switch (cl) {
153 case TC_H_MIN(TC_H_MIN_INGRESS):
Jiri Pirko6529eab2017-05-17 11:07:55 +0200154 return q->ingress_block;
Daniel Borkmann1f211a12016-01-07 22:29:47 +0100155 case TC_H_MIN(TC_H_MIN_EGRESS):
Jiri Pirko6529eab2017-05-17 11:07:55 +0200156 return q->egress_block;
Daniel Borkmann1f211a12016-01-07 22:29:47 +0100157 default:
158 return NULL;
159 }
160}
161
162static int clsact_init(struct Qdisc *sch, struct nlattr *opt)
163{
Jiri Pirko6529eab2017-05-17 11:07:55 +0200164 struct clsact_sched_data *q = qdisc_priv(sch);
165 struct net_device *dev = qdisc_dev(sch);
166 int err;
167
168 err = tcf_block_get(&q->ingress_block, &dev->ingress_cl_list);
169 if (err)
170 return err;
171
172 err = tcf_block_get(&q->egress_block, &dev->egress_cl_list);
173 if (err)
174 return err;
175
Daniel Borkmann1f211a12016-01-07 22:29:47 +0100176 net_inc_ingress_queue();
177 net_inc_egress_queue();
178
179 sch->flags |= TCQ_F_CPUSTATS;
180
181 return 0;
182}
183
184static void clsact_destroy(struct Qdisc *sch)
185{
Jiri Pirko6529eab2017-05-17 11:07:55 +0200186 struct clsact_sched_data *q = qdisc_priv(sch);
Daniel Borkmann1f211a12016-01-07 22:29:47 +0100187
Jiri Pirko6529eab2017-05-17 11:07:55 +0200188 tcf_block_put(q->egress_block);
189 tcf_block_put(q->ingress_block);
Daniel Borkmann1f211a12016-01-07 22:29:47 +0100190
191 net_dec_ingress_queue();
192 net_dec_egress_queue();
193}
194
195static const struct Qdisc_class_ops clsact_class_ops = {
196 .leaf = ingress_leaf,
197 .get = clsact_get,
198 .put = ingress_put,
199 .walk = ingress_walk,
Jiri Pirko6529eab2017-05-17 11:07:55 +0200200 .tcf_block = clsact_tcf_block,
Daniel Borkmann92c075d2016-06-06 22:50:39 +0200201 .tcf_cl_offload = clsact_cl_offload,
Daniel Borkmann1f211a12016-01-07 22:29:47 +0100202 .bind_tcf = clsact_bind_filter,
203 .unbind_tcf = ingress_put,
204};
205
206static struct Qdisc_ops clsact_qdisc_ops __read_mostly = {
207 .cl_ops = &clsact_class_ops,
208 .id = "clsact",
Jiri Pirko6529eab2017-05-17 11:07:55 +0200209 .priv_size = sizeof(struct clsact_sched_data),
Daniel Borkmann1f211a12016-01-07 22:29:47 +0100210 .init = clsact_init,
211 .destroy = clsact_destroy,
212 .dump = ingress_dump,
213 .owner = THIS_MODULE,
214};
215
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216static int __init ingress_module_init(void)
217{
Daniel Borkmann1f211a12016-01-07 22:29:47 +0100218 int ret;
219
220 ret = register_qdisc(&ingress_qdisc_ops);
221 if (!ret) {
222 ret = register_qdisc(&clsact_qdisc_ops);
223 if (ret)
224 unregister_qdisc(&ingress_qdisc_ops);
225 }
226
227 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228}
Patrick McHardy58f4df42008-01-21 00:11:01 -0800229
YOSHIFUJI Hideaki10297b92007-02-09 23:25:16 +0900230static void __exit ingress_module_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231{
232 unregister_qdisc(&ingress_qdisc_ops);
Daniel Borkmann1f211a12016-01-07 22:29:47 +0100233 unregister_qdisc(&clsact_qdisc_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234}
Patrick McHardy58f4df42008-01-21 00:11:01 -0800235
Daniel Borkmannd2788d32015-05-09 22:51:32 +0200236module_init(ingress_module_init);
237module_exit(ingress_module_exit);
238
Daniel Borkmann1f211a12016-01-07 22:29:47 +0100239MODULE_ALIAS("sch_clsact");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240MODULE_LICENSE("GPL");