0001
0002
0003
0004
0005
0006
0007 #include <linux/module.h>
0008 #include <linux/types.h>
0009 #include <linux/list.h>
0010 #include <linux/skbuff.h>
0011 #include <linux/rtnetlink.h>
0012
0013 #include <net/netlink.h>
0014 #include <net/pkt_sched.h>
0015 #include <net/pkt_cls.h>
0016
0017 struct ingress_sched_data {
0018 struct tcf_block *block;
0019 struct tcf_block_ext_info block_info;
0020 struct mini_Qdisc_pair miniqp;
0021 };
0022
0023 static struct Qdisc *ingress_leaf(struct Qdisc *sch, unsigned long arg)
0024 {
0025 return NULL;
0026 }
0027
0028 static unsigned long ingress_find(struct Qdisc *sch, u32 classid)
0029 {
0030 return TC_H_MIN(classid) + 1;
0031 }
0032
0033 static unsigned long ingress_bind_filter(struct Qdisc *sch,
0034 unsigned long parent, u32 classid)
0035 {
0036 return ingress_find(sch, classid);
0037 }
0038
0039 static void ingress_unbind_filter(struct Qdisc *sch, unsigned long cl)
0040 {
0041 }
0042
0043 static void ingress_walk(struct Qdisc *sch, struct qdisc_walker *walker)
0044 {
0045 }
0046
0047 static struct tcf_block *ingress_tcf_block(struct Qdisc *sch, unsigned long cl,
0048 struct netlink_ext_ack *extack)
0049 {
0050 struct ingress_sched_data *q = qdisc_priv(sch);
0051
0052 return q->block;
0053 }
0054
0055 static void clsact_chain_head_change(struct tcf_proto *tp_head, void *priv)
0056 {
0057 struct mini_Qdisc_pair *miniqp = priv;
0058
0059 mini_qdisc_pair_swap(miniqp, tp_head);
0060 };
0061
0062 static void ingress_ingress_block_set(struct Qdisc *sch, u32 block_index)
0063 {
0064 struct ingress_sched_data *q = qdisc_priv(sch);
0065
0066 q->block_info.block_index = block_index;
0067 }
0068
0069 static u32 ingress_ingress_block_get(struct Qdisc *sch)
0070 {
0071 struct ingress_sched_data *q = qdisc_priv(sch);
0072
0073 return q->block_info.block_index;
0074 }
0075
0076 static int ingress_init(struct Qdisc *sch, struct nlattr *opt,
0077 struct netlink_ext_ack *extack)
0078 {
0079 struct ingress_sched_data *q = qdisc_priv(sch);
0080 struct net_device *dev = qdisc_dev(sch);
0081 int err;
0082
0083 net_inc_ingress_queue();
0084
0085 mini_qdisc_pair_init(&q->miniqp, sch, &dev->miniq_ingress);
0086
0087 q->block_info.binder_type = FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS;
0088 q->block_info.chain_head_change = clsact_chain_head_change;
0089 q->block_info.chain_head_change_priv = &q->miniqp;
0090
0091 err = tcf_block_get_ext(&q->block, sch, &q->block_info, extack);
0092 if (err)
0093 return err;
0094
0095 mini_qdisc_pair_block_init(&q->miniqp, q->block);
0096
0097 return 0;
0098 }
0099
0100 static void ingress_destroy(struct Qdisc *sch)
0101 {
0102 struct ingress_sched_data *q = qdisc_priv(sch);
0103
0104 tcf_block_put_ext(q->block, sch, &q->block_info);
0105 net_dec_ingress_queue();
0106 }
0107
0108 static int ingress_dump(struct Qdisc *sch, struct sk_buff *skb)
0109 {
0110 struct nlattr *nest;
0111
0112 nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
0113 if (nest == NULL)
0114 goto nla_put_failure;
0115
0116 return nla_nest_end(skb, nest);
0117
0118 nla_put_failure:
0119 nla_nest_cancel(skb, nest);
0120 return -1;
0121 }
0122
0123 static const struct Qdisc_class_ops ingress_class_ops = {
0124 .flags = QDISC_CLASS_OPS_DOIT_UNLOCKED,
0125 .leaf = ingress_leaf,
0126 .find = ingress_find,
0127 .walk = ingress_walk,
0128 .tcf_block = ingress_tcf_block,
0129 .bind_tcf = ingress_bind_filter,
0130 .unbind_tcf = ingress_unbind_filter,
0131 };
0132
0133 static struct Qdisc_ops ingress_qdisc_ops __read_mostly = {
0134 .cl_ops = &ingress_class_ops,
0135 .id = "ingress",
0136 .priv_size = sizeof(struct ingress_sched_data),
0137 .static_flags = TCQ_F_CPUSTATS,
0138 .init = ingress_init,
0139 .destroy = ingress_destroy,
0140 .dump = ingress_dump,
0141 .ingress_block_set = ingress_ingress_block_set,
0142 .ingress_block_get = ingress_ingress_block_get,
0143 .owner = THIS_MODULE,
0144 };
0145
0146 struct clsact_sched_data {
0147 struct tcf_block *ingress_block;
0148 struct tcf_block *egress_block;
0149 struct tcf_block_ext_info ingress_block_info;
0150 struct tcf_block_ext_info egress_block_info;
0151 struct mini_Qdisc_pair miniqp_ingress;
0152 struct mini_Qdisc_pair miniqp_egress;
0153 };
0154
0155 static unsigned long clsact_find(struct Qdisc *sch, u32 classid)
0156 {
0157 switch (TC_H_MIN(classid)) {
0158 case TC_H_MIN(TC_H_MIN_INGRESS):
0159 case TC_H_MIN(TC_H_MIN_EGRESS):
0160 return TC_H_MIN(classid);
0161 default:
0162 return 0;
0163 }
0164 }
0165
0166 static unsigned long clsact_bind_filter(struct Qdisc *sch,
0167 unsigned long parent, u32 classid)
0168 {
0169 return clsact_find(sch, classid);
0170 }
0171
0172 static struct tcf_block *clsact_tcf_block(struct Qdisc *sch, unsigned long cl,
0173 struct netlink_ext_ack *extack)
0174 {
0175 struct clsact_sched_data *q = qdisc_priv(sch);
0176
0177 switch (cl) {
0178 case TC_H_MIN(TC_H_MIN_INGRESS):
0179 return q->ingress_block;
0180 case TC_H_MIN(TC_H_MIN_EGRESS):
0181 return q->egress_block;
0182 default:
0183 return NULL;
0184 }
0185 }
0186
0187 static void clsact_ingress_block_set(struct Qdisc *sch, u32 block_index)
0188 {
0189 struct clsact_sched_data *q = qdisc_priv(sch);
0190
0191 q->ingress_block_info.block_index = block_index;
0192 }
0193
0194 static void clsact_egress_block_set(struct Qdisc *sch, u32 block_index)
0195 {
0196 struct clsact_sched_data *q = qdisc_priv(sch);
0197
0198 q->egress_block_info.block_index = block_index;
0199 }
0200
0201 static u32 clsact_ingress_block_get(struct Qdisc *sch)
0202 {
0203 struct clsact_sched_data *q = qdisc_priv(sch);
0204
0205 return q->ingress_block_info.block_index;
0206 }
0207
0208 static u32 clsact_egress_block_get(struct Qdisc *sch)
0209 {
0210 struct clsact_sched_data *q = qdisc_priv(sch);
0211
0212 return q->egress_block_info.block_index;
0213 }
0214
0215 static int clsact_init(struct Qdisc *sch, struct nlattr *opt,
0216 struct netlink_ext_ack *extack)
0217 {
0218 struct clsact_sched_data *q = qdisc_priv(sch);
0219 struct net_device *dev = qdisc_dev(sch);
0220 int err;
0221
0222 net_inc_ingress_queue();
0223 net_inc_egress_queue();
0224
0225 mini_qdisc_pair_init(&q->miniqp_ingress, sch, &dev->miniq_ingress);
0226
0227 q->ingress_block_info.binder_type = FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS;
0228 q->ingress_block_info.chain_head_change = clsact_chain_head_change;
0229 q->ingress_block_info.chain_head_change_priv = &q->miniqp_ingress;
0230
0231 err = tcf_block_get_ext(&q->ingress_block, sch, &q->ingress_block_info,
0232 extack);
0233 if (err)
0234 return err;
0235
0236 mini_qdisc_pair_block_init(&q->miniqp_ingress, q->ingress_block);
0237
0238 mini_qdisc_pair_init(&q->miniqp_egress, sch, &dev->miniq_egress);
0239
0240 q->egress_block_info.binder_type = FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS;
0241 q->egress_block_info.chain_head_change = clsact_chain_head_change;
0242 q->egress_block_info.chain_head_change_priv = &q->miniqp_egress;
0243
0244 return tcf_block_get_ext(&q->egress_block, sch, &q->egress_block_info, extack);
0245 }
0246
0247 static void clsact_destroy(struct Qdisc *sch)
0248 {
0249 struct clsact_sched_data *q = qdisc_priv(sch);
0250
0251 tcf_block_put_ext(q->egress_block, sch, &q->egress_block_info);
0252 tcf_block_put_ext(q->ingress_block, sch, &q->ingress_block_info);
0253
0254 net_dec_ingress_queue();
0255 net_dec_egress_queue();
0256 }
0257
0258 static const struct Qdisc_class_ops clsact_class_ops = {
0259 .flags = QDISC_CLASS_OPS_DOIT_UNLOCKED,
0260 .leaf = ingress_leaf,
0261 .find = clsact_find,
0262 .walk = ingress_walk,
0263 .tcf_block = clsact_tcf_block,
0264 .bind_tcf = clsact_bind_filter,
0265 .unbind_tcf = ingress_unbind_filter,
0266 };
0267
0268 static struct Qdisc_ops clsact_qdisc_ops __read_mostly = {
0269 .cl_ops = &clsact_class_ops,
0270 .id = "clsact",
0271 .priv_size = sizeof(struct clsact_sched_data),
0272 .static_flags = TCQ_F_CPUSTATS,
0273 .init = clsact_init,
0274 .destroy = clsact_destroy,
0275 .dump = ingress_dump,
0276 .ingress_block_set = clsact_ingress_block_set,
0277 .egress_block_set = clsact_egress_block_set,
0278 .ingress_block_get = clsact_ingress_block_get,
0279 .egress_block_get = clsact_egress_block_get,
0280 .owner = THIS_MODULE,
0281 };
0282
0283 static int __init ingress_module_init(void)
0284 {
0285 int ret;
0286
0287 ret = register_qdisc(&ingress_qdisc_ops);
0288 if (!ret) {
0289 ret = register_qdisc(&clsact_qdisc_ops);
0290 if (ret)
0291 unregister_qdisc(&ingress_qdisc_ops);
0292 }
0293
0294 return ret;
0295 }
0296
0297 static void __exit ingress_module_exit(void)
0298 {
0299 unregister_qdisc(&ingress_qdisc_ops);
0300 unregister_qdisc(&clsact_qdisc_ops);
0301 }
0302
0303 module_init(ingress_module_init);
0304 module_exit(ingress_module_exit);
0305
0306 MODULE_ALIAS("sch_clsact");
0307 MODULE_LICENSE("GPL");