summaryrefslogtreecommitdiffstats
path: root/net/sched/sch_ingress.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched/sch_ingress.c')
-rw-r--r--net/sched/sch_ingress.c88
1 files changed, 86 insertions, 2 deletions
diff --git a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c
index e7c648fa9dc3..10adbc617905 100644
--- a/net/sched/sch_ingress.c
+++ b/net/sched/sch_ingress.c
@@ -1,4 +1,5 @@
-/* net/sched/sch_ingress.c - Ingress qdisc
+/* net/sched/sch_ingress.c - Ingress and clsact qdisc
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -98,17 +99,100 @@ static struct Qdisc_ops ingress_qdisc_ops __read_mostly = {
.owner = THIS_MODULE,
};
+static unsigned long clsact_get(struct Qdisc *sch, u32 classid)
+{
+ switch (TC_H_MIN(classid)) {
+ case TC_H_MIN(TC_H_MIN_INGRESS):
+ case TC_H_MIN(TC_H_MIN_EGRESS):
+ return TC_H_MIN(classid);
+ default:
+ return 0;
+ }
+}
+
+static unsigned long clsact_bind_filter(struct Qdisc *sch,
+ unsigned long parent, u32 classid)
+{
+ return clsact_get(sch, classid);
+}
+
+static struct tcf_proto __rcu **clsact_find_tcf(struct Qdisc *sch,
+ unsigned long cl)
+{
+ struct net_device *dev = qdisc_dev(sch);
+
+ switch (cl) {
+ case TC_H_MIN(TC_H_MIN_INGRESS):
+ return &dev->ingress_cl_list;
+ case TC_H_MIN(TC_H_MIN_EGRESS):
+ return &dev->egress_cl_list;
+ default:
+ return NULL;
+ }
+}
+
+static int clsact_init(struct Qdisc *sch, struct nlattr *opt)
+{
+ net_inc_ingress_queue();
+ net_inc_egress_queue();
+
+ sch->flags |= TCQ_F_CPUSTATS;
+
+ return 0;
+}
+
+static void clsact_destroy(struct Qdisc *sch)
+{
+ struct net_device *dev = qdisc_dev(sch);
+
+ tcf_destroy_chain(&dev->ingress_cl_list);
+ tcf_destroy_chain(&dev->egress_cl_list);
+
+ net_dec_ingress_queue();
+ net_dec_egress_queue();
+}
+
+static const struct Qdisc_class_ops clsact_class_ops = {
+ .leaf = ingress_leaf,
+ .get = clsact_get,
+ .put = ingress_put,
+ .walk = ingress_walk,
+ .tcf_chain = clsact_find_tcf,
+ .bind_tcf = clsact_bind_filter,
+ .unbind_tcf = ingress_put,
+};
+
+static struct Qdisc_ops clsact_qdisc_ops __read_mostly = {
+ .cl_ops = &clsact_class_ops,
+ .id = "clsact",
+ .init = clsact_init,
+ .destroy = clsact_destroy,
+ .dump = ingress_dump,
+ .owner = THIS_MODULE,
+};
+
static int __init ingress_module_init(void)
{
- return register_qdisc(&ingress_qdisc_ops);
+ int ret;
+
+ ret = register_qdisc(&ingress_qdisc_ops);
+ if (!ret) {
+ ret = register_qdisc(&clsact_qdisc_ops);
+ if (ret)
+ unregister_qdisc(&ingress_qdisc_ops);
+ }
+
+ return ret;
}
static void __exit ingress_module_exit(void)
{
unregister_qdisc(&ingress_qdisc_ops);
+ unregister_qdisc(&clsact_qdisc_ops);
}
module_init(ingress_module_init);
module_exit(ingress_module_exit);
+MODULE_ALIAS("sch_clsact");
MODULE_LICENSE("GPL");