blob: 3372dd5e984da3d275325f20e8ada9dd0552dafb [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;
Jiri Pirko6e40cf22017-10-19 15:50:30 +020023 struct tcf_block_ext_info block_info;
Jiri Pirko46209402017-11-03 11:46:25 +010024 struct mini_Qdisc_pair miniqp;
Jiri Pirko6529eab2017-05-17 11:07:55 +020025};
26
Linus Torvalds1da177e2005-04-16 15:20:36 -070027static struct Qdisc *ingress_leaf(struct Qdisc *sch, unsigned long arg)
28{
29 return NULL;
30}
31
WANG Cong143976c2017-08-24 16:51:29 -070032static unsigned long ingress_find(struct Qdisc *sch, u32 classid)
Linus Torvalds1da177e2005-04-16 15:20:36 -070033{
Linus Torvalds1da177e2005-04-16 15:20:36 -070034 return TC_H_MIN(classid) + 1;
35}
36
Linus Torvalds1da177e2005-04-16 15:20:36 -070037static unsigned long ingress_bind_filter(struct Qdisc *sch,
Patrick McHardy58f4df42008-01-21 00:11:01 -080038 unsigned long parent, u32 classid)
Linus Torvalds1da177e2005-04-16 15:20:36 -070039{
WANG Cong143976c2017-08-24 16:51:29 -070040 return ingress_find(sch, classid);
Linus Torvalds1da177e2005-04-16 15:20:36 -070041}
42
WANG Cong143976c2017-08-24 16:51:29 -070043static void ingress_unbind_filter(struct Qdisc *sch, unsigned long cl)
Linus Torvalds1da177e2005-04-16 15:20:36 -070044{
45}
46
Patrick McHardy58f4df42008-01-21 00:11:01 -080047static void ingress_walk(struct Qdisc *sch, struct qdisc_walker *walker)
Linus Torvalds1da177e2005-04-16 15:20:36 -070048{
Linus Torvalds1da177e2005-04-16 15:20:36 -070049}
50
Alexander Aringcbaacc42017-12-20 12:35:16 -050051static struct tcf_block *ingress_tcf_block(struct Qdisc *sch, unsigned long cl,
52 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -070053{
Jiri Pirko6529eab2017-05-17 11:07:55 +020054 struct ingress_sched_data *q = qdisc_priv(sch);
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
Jiri Pirko6529eab2017-05-17 11:07:55 +020056 return q->block;
Linus Torvalds1da177e2005-04-16 15:20:36 -070057}
58
Jiri Pirkoc7eb7d72017-11-03 11:46:24 +010059static void clsact_chain_head_change(struct tcf_proto *tp_head, void *priv)
60{
Jiri Pirko46209402017-11-03 11:46:25 +010061 struct mini_Qdisc_pair *miniqp = priv;
Jiri Pirkoc7eb7d72017-11-03 11:46:24 +010062
Jiri Pirko46209402017-11-03 11:46:25 +010063 mini_qdisc_pair_swap(miniqp, tp_head);
Jiri Pirkoc7eb7d72017-11-03 11:46:24 +010064}
65
Alexander Aringe63d7df2017-12-20 12:35:13 -050066static int ingress_init(struct Qdisc *sch, struct nlattr *opt,
67 struct netlink_ext_ack *extack)
Daniel Borkmann45771392015-04-10 23:07:54 +020068{
Jiri Pirko6529eab2017-05-17 11:07:55 +020069 struct ingress_sched_data *q = qdisc_priv(sch);
70 struct net_device *dev = qdisc_dev(sch);
Jiri Pirko6529eab2017-05-17 11:07:55 +020071
Jiri Pirkob59e6972017-12-15 12:40:13 +010072 net_inc_ingress_queue();
73
Jiri Pirko46209402017-11-03 11:46:25 +010074 mini_qdisc_pair_init(&q->miniqp, sch, &dev->miniq_ingress);
75
Jiri Pirko6e40cf22017-10-19 15:50:30 +020076 q->block_info.binder_type = TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS;
Jiri Pirkoc7eb7d72017-11-03 11:46:24 +010077 q->block_info.chain_head_change = clsact_chain_head_change;
Jiri Pirko46209402017-11-03 11:46:25 +010078 q->block_info.chain_head_change_priv = &q->miniqp;
Jiri Pirko6e40cf22017-10-19 15:50:30 +020079
David S. Millerc02b3742018-01-17 00:00:25 -050080 return tcf_block_get_ext(&q->block, sch, &q->block_info, extack);
Daniel Borkmann45771392015-04-10 23:07:54 +020081}
82
Linus Torvalds1da177e2005-04-16 15:20:36 -070083static void ingress_destroy(struct Qdisc *sch)
84{
Jiri Pirko6529eab2017-05-17 11:07:55 +020085 struct ingress_sched_data *q = qdisc_priv(sch);
Linus Torvalds1da177e2005-04-16 15:20:36 -070086
Jiri Pirkoc7eb7d72017-11-03 11:46:24 +010087 tcf_block_put_ext(q->block, sch, &q->block_info);
Daniel Borkmann45771392015-04-10 23:07:54 +020088 net_dec_ingress_queue();
Linus Torvalds1da177e2005-04-16 15:20:36 -070089}
90
Linus Torvalds1da177e2005-04-16 15:20:36 -070091static int ingress_dump(struct Qdisc *sch, struct sk_buff *skb)
92{
Patrick McHardy4b3550ef2008-01-23 20:34:11 -080093 struct nlattr *nest;
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
Patrick McHardy4b3550ef2008-01-23 20:34:11 -080095 nest = nla_nest_start(skb, TCA_OPTIONS);
96 if (nest == NULL)
97 goto nla_put_failure;
Daniel Borkmannd2788d32015-05-09 22:51:32 +020098
Yang Yingliangd59b7d82014-03-12 10:20:32 +080099 return nla_nest_end(skb, nest);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100
Patrick McHardy1e904742008-01-22 22:11:17 -0800101nla_put_failure:
Patrick McHardy4b3550ef2008-01-23 20:34:11 -0800102 nla_nest_cancel(skb, nest);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 return -1;
104}
105
Eric Dumazet20fea082007-11-14 01:44:41 -0800106static const struct Qdisc_class_ops ingress_class_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 .leaf = ingress_leaf,
WANG Cong143976c2017-08-24 16:51:29 -0700108 .find = ingress_find,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 .walk = ingress_walk,
Jiri Pirko6529eab2017-05-17 11:07:55 +0200110 .tcf_block = ingress_tcf_block,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 .bind_tcf = ingress_bind_filter,
WANG Cong143976c2017-08-24 16:51:29 -0700112 .unbind_tcf = ingress_unbind_filter,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113};
114
Eric Dumazet20fea082007-11-14 01:44:41 -0800115static struct Qdisc_ops ingress_qdisc_ops __read_mostly = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 .cl_ops = &ingress_class_ops,
117 .id = "ingress",
Jiri Pirko6529eab2017-05-17 11:07:55 +0200118 .priv_size = sizeof(struct ingress_sched_data),
Daniel Borkmann81d947e2018-01-15 23:12:09 +0100119 .static_flags = TCQ_F_CPUSTATS,
Daniel Borkmann45771392015-04-10 23:07:54 +0200120 .init = ingress_init,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 .destroy = ingress_destroy,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122 .dump = ingress_dump,
123 .owner = THIS_MODULE,
124};
125
Jiri Pirko6529eab2017-05-17 11:07:55 +0200126struct clsact_sched_data {
127 struct tcf_block *ingress_block;
128 struct tcf_block *egress_block;
Jiri Pirko6e40cf22017-10-19 15:50:30 +0200129 struct tcf_block_ext_info ingress_block_info;
130 struct tcf_block_ext_info egress_block_info;
Jiri Pirko46209402017-11-03 11:46:25 +0100131 struct mini_Qdisc_pair miniqp_ingress;
132 struct mini_Qdisc_pair miniqp_egress;
Jiri Pirko6529eab2017-05-17 11:07:55 +0200133};
134
WANG Cong143976c2017-08-24 16:51:29 -0700135static unsigned long clsact_find(struct Qdisc *sch, u32 classid)
Daniel Borkmann1f211a12016-01-07 22:29:47 +0100136{
137 switch (TC_H_MIN(classid)) {
138 case TC_H_MIN(TC_H_MIN_INGRESS):
139 case TC_H_MIN(TC_H_MIN_EGRESS):
140 return TC_H_MIN(classid);
141 default:
142 return 0;
143 }
144}
145
146static unsigned long clsact_bind_filter(struct Qdisc *sch,
147 unsigned long parent, u32 classid)
148{
WANG Cong143976c2017-08-24 16:51:29 -0700149 return clsact_find(sch, classid);
Daniel Borkmann1f211a12016-01-07 22:29:47 +0100150}
151
Alexander Aringcbaacc42017-12-20 12:35:16 -0500152static struct tcf_block *clsact_tcf_block(struct Qdisc *sch, unsigned long cl,
153 struct netlink_ext_ack *extack)
Daniel Borkmann1f211a12016-01-07 22:29:47 +0100154{
Jiri Pirko6529eab2017-05-17 11:07:55 +0200155 struct clsact_sched_data *q = qdisc_priv(sch);
Daniel Borkmann1f211a12016-01-07 22:29:47 +0100156
157 switch (cl) {
158 case TC_H_MIN(TC_H_MIN_INGRESS):
Jiri Pirko6529eab2017-05-17 11:07:55 +0200159 return q->ingress_block;
Daniel Borkmann1f211a12016-01-07 22:29:47 +0100160 case TC_H_MIN(TC_H_MIN_EGRESS):
Jiri Pirko6529eab2017-05-17 11:07:55 +0200161 return q->egress_block;
Daniel Borkmann1f211a12016-01-07 22:29:47 +0100162 default:
163 return NULL;
164 }
165}
166
Alexander Aringe63d7df2017-12-20 12:35:13 -0500167static int clsact_init(struct Qdisc *sch, struct nlattr *opt,
168 struct netlink_ext_ack *extack)
Daniel Borkmann1f211a12016-01-07 22:29:47 +0100169{
Jiri Pirko6529eab2017-05-17 11:07:55 +0200170 struct clsact_sched_data *q = qdisc_priv(sch);
171 struct net_device *dev = qdisc_dev(sch);
172 int err;
173
Jiri Pirkob59e6972017-12-15 12:40:13 +0100174 net_inc_ingress_queue();
175 net_inc_egress_queue();
176
Jiri Pirko46209402017-11-03 11:46:25 +0100177 mini_qdisc_pair_init(&q->miniqp_ingress, sch, &dev->miniq_ingress);
178
Jiri Pirko6e40cf22017-10-19 15:50:30 +0200179 q->ingress_block_info.binder_type = TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS;
Jiri Pirkoc7eb7d72017-11-03 11:46:24 +0100180 q->ingress_block_info.chain_head_change = clsact_chain_head_change;
Jiri Pirko46209402017-11-03 11:46:25 +0100181 q->ingress_block_info.chain_head_change_priv = &q->miniqp_ingress;
Jiri Pirko6e40cf22017-10-19 15:50:30 +0200182
Alexander Aring8d1a77f2017-12-20 12:35:19 -0500183 err = tcf_block_get_ext(&q->ingress_block, sch, &q->ingress_block_info,
184 extack);
Jiri Pirko6529eab2017-05-17 11:07:55 +0200185 if (err)
186 return err;
187
Jiri Pirko46209402017-11-03 11:46:25 +0100188 mini_qdisc_pair_init(&q->miniqp_egress, sch, &dev->miniq_egress);
189
Jiri Pirko6e40cf22017-10-19 15:50:30 +0200190 q->egress_block_info.binder_type = TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS;
Jiri Pirkoc7eb7d72017-11-03 11:46:24 +0100191 q->egress_block_info.chain_head_change = clsact_chain_head_change;
Jiri Pirko46209402017-11-03 11:46:25 +0100192 q->egress_block_info.chain_head_change_priv = &q->miniqp_egress;
Jiri Pirko6e40cf22017-10-19 15:50:30 +0200193
David S. Millerc02b3742018-01-17 00:00:25 -0500194 return tcf_block_get_ext(&q->egress_block, sch, &q->egress_block_info, extack);
Daniel Borkmann1f211a12016-01-07 22:29:47 +0100195}
196
197static void clsact_destroy(struct Qdisc *sch)
198{
Jiri Pirko6529eab2017-05-17 11:07:55 +0200199 struct clsact_sched_data *q = qdisc_priv(sch);
Daniel Borkmann1f211a12016-01-07 22:29:47 +0100200
Jiri Pirkoc7eb7d72017-11-03 11:46:24 +0100201 tcf_block_put_ext(q->egress_block, sch, &q->egress_block_info);
202 tcf_block_put_ext(q->ingress_block, sch, &q->ingress_block_info);
Daniel Borkmann1f211a12016-01-07 22:29:47 +0100203
204 net_dec_ingress_queue();
205 net_dec_egress_queue();
206}
207
208static const struct Qdisc_class_ops clsact_class_ops = {
209 .leaf = ingress_leaf,
WANG Cong143976c2017-08-24 16:51:29 -0700210 .find = clsact_find,
Daniel Borkmann1f211a12016-01-07 22:29:47 +0100211 .walk = ingress_walk,
Jiri Pirko6529eab2017-05-17 11:07:55 +0200212 .tcf_block = clsact_tcf_block,
Daniel Borkmann1f211a12016-01-07 22:29:47 +0100213 .bind_tcf = clsact_bind_filter,
WANG Cong143976c2017-08-24 16:51:29 -0700214 .unbind_tcf = ingress_unbind_filter,
Daniel Borkmann1f211a12016-01-07 22:29:47 +0100215};
216
217static struct Qdisc_ops clsact_qdisc_ops __read_mostly = {
218 .cl_ops = &clsact_class_ops,
219 .id = "clsact",
Jiri Pirko6529eab2017-05-17 11:07:55 +0200220 .priv_size = sizeof(struct clsact_sched_data),
Daniel Borkmann81d947e2018-01-15 23:12:09 +0100221 .static_flags = TCQ_F_CPUSTATS,
Daniel Borkmann1f211a12016-01-07 22:29:47 +0100222 .init = clsact_init,
223 .destroy = clsact_destroy,
224 .dump = ingress_dump,
225 .owner = THIS_MODULE,
226};
227
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228static int __init ingress_module_init(void)
229{
Daniel Borkmann1f211a12016-01-07 22:29:47 +0100230 int ret;
231
232 ret = register_qdisc(&ingress_qdisc_ops);
233 if (!ret) {
234 ret = register_qdisc(&clsact_qdisc_ops);
235 if (ret)
236 unregister_qdisc(&ingress_qdisc_ops);
237 }
238
239 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240}
Patrick McHardy58f4df42008-01-21 00:11:01 -0800241
YOSHIFUJI Hideaki10297b92007-02-09 23:25:16 +0900242static void __exit ingress_module_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243{
244 unregister_qdisc(&ingress_qdisc_ops);
Daniel Borkmann1f211a12016-01-07 22:29:47 +0100245 unregister_qdisc(&clsact_qdisc_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246}
Patrick McHardy58f4df42008-01-21 00:11:01 -0800247
Daniel Borkmannd2788d32015-05-09 22:51:32 +0200248module_init(ingress_module_init);
249module_exit(ingress_module_exit);
250
Daniel Borkmann1f211a12016-01-07 22:29:47 +0100251MODULE_ALIAS("sch_clsact");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252MODULE_LICENSE("GPL");