12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21f211a1bSDaniel Borkmann /* net/sched/sch_ingress.c - Ingress and clsact qdisc
31f211a1bSDaniel Borkmann *
41da177e4SLinus Torvalds * Authors: Jamal Hadi Salim 1999
51da177e4SLinus Torvalds */
61da177e4SLinus Torvalds
71da177e4SLinus Torvalds #include <linux/module.h>
81da177e4SLinus Torvalds #include <linux/types.h>
90ba48053SPatrick McHardy #include <linux/list.h>
101da177e4SLinus Torvalds #include <linux/skbuff.h>
111da177e4SLinus Torvalds #include <linux/rtnetlink.h>
12d2788d34SDaniel Borkmann
13dc5fc579SArnaldo Carvalho de Melo #include <net/netlink.h>
141da177e4SLinus Torvalds #include <net/pkt_sched.h>
15cf1facdaSJiri Pirko #include <net/pkt_cls.h>
16e420bed0SDaniel Borkmann #include <net/tcx.h>
171da177e4SLinus Torvalds
186529eabaSJiri Pirko struct ingress_sched_data {
196529eabaSJiri Pirko struct tcf_block *block;
206e40cf2dSJiri Pirko struct tcf_block_ext_info block_info;
2146209401SJiri Pirko struct mini_Qdisc_pair miniqp;
226529eabaSJiri Pirko };
236529eabaSJiri Pirko
ingress_leaf(struct Qdisc * sch,unsigned long arg)241da177e4SLinus Torvalds static struct Qdisc *ingress_leaf(struct Qdisc *sch, unsigned long arg)
251da177e4SLinus Torvalds {
261da177e4SLinus Torvalds return NULL;
271da177e4SLinus Torvalds }
281da177e4SLinus Torvalds
ingress_find(struct Qdisc * sch,u32 classid)29143976ceSWANG Cong static unsigned long ingress_find(struct Qdisc *sch, u32 classid)
301da177e4SLinus Torvalds {
311da177e4SLinus Torvalds return TC_H_MIN(classid) + 1;
321da177e4SLinus Torvalds }
331da177e4SLinus Torvalds
ingress_bind_filter(struct Qdisc * sch,unsigned long parent,u32 classid)341da177e4SLinus Torvalds static unsigned long ingress_bind_filter(struct Qdisc *sch,
351da177e4SLinus Torvalds unsigned long parent, u32 classid)
361da177e4SLinus Torvalds {
37143976ceSWANG Cong return ingress_find(sch, classid);
381da177e4SLinus Torvalds }
391da177e4SLinus Torvalds
ingress_unbind_filter(struct Qdisc * sch,unsigned long cl)40143976ceSWANG Cong static void ingress_unbind_filter(struct Qdisc *sch, unsigned long cl)
411da177e4SLinus Torvalds {
421da177e4SLinus Torvalds }
431da177e4SLinus Torvalds
ingress_walk(struct Qdisc * sch,struct qdisc_walker * walker)441da177e4SLinus Torvalds static void ingress_walk(struct Qdisc *sch, struct qdisc_walker *walker)
451da177e4SLinus Torvalds {
461da177e4SLinus Torvalds }
471da177e4SLinus Torvalds
ingress_tcf_block(struct Qdisc * sch,unsigned long cl,struct netlink_ext_ack * extack)48cbaacc4eSAlexander Aring static struct tcf_block *ingress_tcf_block(struct Qdisc *sch, unsigned long cl,
49cbaacc4eSAlexander Aring struct netlink_ext_ack *extack)
501da177e4SLinus Torvalds {
516529eabaSJiri Pirko struct ingress_sched_data *q = qdisc_priv(sch);
521da177e4SLinus Torvalds
536529eabaSJiri Pirko return q->block;
541da177e4SLinus Torvalds }
551da177e4SLinus Torvalds
clsact_chain_head_change(struct tcf_proto * tp_head,void * priv)56c7eb7d72SJiri Pirko static void clsact_chain_head_change(struct tcf_proto *tp_head, void *priv)
57c7eb7d72SJiri Pirko {
5846209401SJiri Pirko struct mini_Qdisc_pair *miniqp = priv;
59c7eb7d72SJiri Pirko
6046209401SJiri Pirko mini_qdisc_pair_swap(miniqp, tp_head);
6151ab2994SJiri Pirko };
6251ab2994SJiri Pirko
ingress_ingress_block_set(struct Qdisc * sch,u32 block_index)6351ab2994SJiri Pirko static void ingress_ingress_block_set(struct Qdisc *sch, u32 block_index)
6451ab2994SJiri Pirko {
6551ab2994SJiri Pirko struct ingress_sched_data *q = qdisc_priv(sch);
6651ab2994SJiri Pirko
6751ab2994SJiri Pirko q->block_info.block_index = block_index;
6851ab2994SJiri Pirko }
6951ab2994SJiri Pirko
ingress_ingress_block_get(struct Qdisc * sch)7051ab2994SJiri Pirko static u32 ingress_ingress_block_get(struct Qdisc *sch)
7151ab2994SJiri Pirko {
7251ab2994SJiri Pirko struct ingress_sched_data *q = qdisc_priv(sch);
7351ab2994SJiri Pirko
7451ab2994SJiri Pirko return q->block_info.block_index;
75c7eb7d72SJiri Pirko }
76c7eb7d72SJiri Pirko
ingress_init(struct Qdisc * sch,struct nlattr * opt,struct netlink_ext_ack * extack)77e63d7dfdSAlexander Aring static int ingress_init(struct Qdisc *sch, struct nlattr *opt,
78e63d7dfdSAlexander Aring struct netlink_ext_ack *extack)
794577139bSDaniel Borkmann {
806529eabaSJiri Pirko struct ingress_sched_data *q = qdisc_priv(sch);
816529eabaSJiri Pirko struct net_device *dev = qdisc_dev(sch);
82e420bed0SDaniel Borkmann struct bpf_mprog_entry *entry;
83e420bed0SDaniel Borkmann bool created;
847d17c544SPaul Blakey int err;
856529eabaSJiri Pirko
86c7cfbd11SPeilin Ye if (sch->parent != TC_H_INGRESS)
87c7cfbd11SPeilin Ye return -EOPNOTSUPP;
88c7cfbd11SPeilin Ye
89b59e6979SJiri Pirko net_inc_ingress_queue();
90b59e6979SJiri Pirko
91e420bed0SDaniel Borkmann entry = tcx_entry_fetch_or_create(dev, true, &created);
92e420bed0SDaniel Borkmann if (!entry)
93e420bed0SDaniel Borkmann return -ENOMEM;
94*230bb136SDaniel Borkmann tcx_miniq_inc(entry);
95e420bed0SDaniel Borkmann mini_qdisc_pair_init(&q->miniqp, sch, &tcx_entry(entry)->miniq);
96e420bed0SDaniel Borkmann if (created)
97e420bed0SDaniel Borkmann tcx_entry_update(dev, entry, true);
9846209401SJiri Pirko
9932f8c409SPablo Neira Ayuso q->block_info.binder_type = FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS;
100c7eb7d72SJiri Pirko q->block_info.chain_head_change = clsact_chain_head_change;
10146209401SJiri Pirko q->block_info.chain_head_change_priv = &q->miniqp;
1026e40cf2dSJiri Pirko
1037d17c544SPaul Blakey err = tcf_block_get_ext(&q->block, sch, &q->block_info, extack);
1047d17c544SPaul Blakey if (err)
1057d17c544SPaul Blakey return err;
1067d17c544SPaul Blakey
1077d17c544SPaul Blakey mini_qdisc_pair_block_init(&q->miniqp, q->block);
1087d17c544SPaul Blakey
1097d17c544SPaul Blakey return 0;
1104577139bSDaniel Borkmann }
1114577139bSDaniel Borkmann
ingress_destroy(struct Qdisc * sch)1121da177e4SLinus Torvalds static void ingress_destroy(struct Qdisc *sch)
1131da177e4SLinus Torvalds {
1146529eabaSJiri Pirko struct ingress_sched_data *q = qdisc_priv(sch);
115e420bed0SDaniel Borkmann struct net_device *dev = qdisc_dev(sch);
116e420bed0SDaniel Borkmann struct bpf_mprog_entry *entry = rtnl_dereference(dev->tcx_ingress);
1171da177e4SLinus Torvalds
118c7cfbd11SPeilin Ye if (sch->parent != TC_H_INGRESS)
119c7cfbd11SPeilin Ye return;
120c7cfbd11SPeilin Ye
121c7eb7d72SJiri Pirko tcf_block_put_ext(q->block, sch, &q->block_info);
122e420bed0SDaniel Borkmann
123e420bed0SDaniel Borkmann if (entry) {
124*230bb136SDaniel Borkmann tcx_miniq_dec(entry);
125e420bed0SDaniel Borkmann if (!tcx_entry_is_active(entry)) {
126dc644b54SDaniel Borkmann tcx_entry_update(dev, NULL, true);
127e420bed0SDaniel Borkmann tcx_entry_free(entry);
128e420bed0SDaniel Borkmann }
129e420bed0SDaniel Borkmann }
130e420bed0SDaniel Borkmann
1314577139bSDaniel Borkmann net_dec_ingress_queue();
1321da177e4SLinus Torvalds }
1331da177e4SLinus Torvalds
ingress_dump(struct Qdisc * sch,struct sk_buff * skb)1341da177e4SLinus Torvalds static int ingress_dump(struct Qdisc *sch, struct sk_buff *skb)
1351da177e4SLinus Torvalds {
1364b3550efSPatrick McHardy struct nlattr *nest;
1371da177e4SLinus Torvalds
138ae0be8deSMichal Kubecek nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
1394b3550efSPatrick McHardy if (nest == NULL)
1404b3550efSPatrick McHardy goto nla_put_failure;
141d2788d34SDaniel Borkmann
142d59b7d80SYang Yingliang return nla_nest_end(skb, nest);
1431da177e4SLinus Torvalds
1441e90474cSPatrick McHardy nla_put_failure:
1454b3550efSPatrick McHardy nla_nest_cancel(skb, nest);
1461da177e4SLinus Torvalds return -1;
1471da177e4SLinus Torvalds }
1481da177e4SLinus Torvalds
14920fea08bSEric Dumazet static const struct Qdisc_class_ops ingress_class_ops = {
1507a096d57SVlad Buslov .flags = QDISC_CLASS_OPS_DOIT_UNLOCKED,
1511da177e4SLinus Torvalds .leaf = ingress_leaf,
152143976ceSWANG Cong .find = ingress_find,
1531da177e4SLinus Torvalds .walk = ingress_walk,
1546529eabaSJiri Pirko .tcf_block = ingress_tcf_block,
1551da177e4SLinus Torvalds .bind_tcf = ingress_bind_filter,
156143976ceSWANG Cong .unbind_tcf = ingress_unbind_filter,
1571da177e4SLinus Torvalds };
1581da177e4SLinus Torvalds
15920fea08bSEric Dumazet static struct Qdisc_ops ingress_qdisc_ops __read_mostly = {
1601da177e4SLinus Torvalds .cl_ops = &ingress_class_ops,
1611da177e4SLinus Torvalds .id = "ingress",
1626529eabaSJiri Pirko .priv_size = sizeof(struct ingress_sched_data),
163f85fa45dSPeilin Ye .static_flags = TCQ_F_INGRESS | TCQ_F_CPUSTATS,
1644577139bSDaniel Borkmann .init = ingress_init,
1651da177e4SLinus Torvalds .destroy = ingress_destroy,
1661da177e4SLinus Torvalds .dump = ingress_dump,
16751ab2994SJiri Pirko .ingress_block_set = ingress_ingress_block_set,
16851ab2994SJiri Pirko .ingress_block_get = ingress_ingress_block_get,
1691da177e4SLinus Torvalds .owner = THIS_MODULE,
1701da177e4SLinus Torvalds };
1711da177e4SLinus Torvalds
1726529eabaSJiri Pirko struct clsact_sched_data {
1736529eabaSJiri Pirko struct tcf_block *ingress_block;
1746529eabaSJiri Pirko struct tcf_block *egress_block;
1756e40cf2dSJiri Pirko struct tcf_block_ext_info ingress_block_info;
1766e40cf2dSJiri Pirko struct tcf_block_ext_info egress_block_info;
17746209401SJiri Pirko struct mini_Qdisc_pair miniqp_ingress;
17846209401SJiri Pirko struct mini_Qdisc_pair miniqp_egress;
1796529eabaSJiri Pirko };
1806529eabaSJiri Pirko
clsact_find(struct Qdisc * sch,u32 classid)181143976ceSWANG Cong static unsigned long clsact_find(struct Qdisc *sch, u32 classid)
1821f211a1bSDaniel Borkmann {
1831f211a1bSDaniel Borkmann switch (TC_H_MIN(classid)) {
1841f211a1bSDaniel Borkmann case TC_H_MIN(TC_H_MIN_INGRESS):
1851f211a1bSDaniel Borkmann case TC_H_MIN(TC_H_MIN_EGRESS):
1861f211a1bSDaniel Borkmann return TC_H_MIN(classid);
1871f211a1bSDaniel Borkmann default:
1881f211a1bSDaniel Borkmann return 0;
1891f211a1bSDaniel Borkmann }
1901f211a1bSDaniel Borkmann }
1911f211a1bSDaniel Borkmann
clsact_bind_filter(struct Qdisc * sch,unsigned long parent,u32 classid)1921f211a1bSDaniel Borkmann static unsigned long clsact_bind_filter(struct Qdisc *sch,
1931f211a1bSDaniel Borkmann unsigned long parent, u32 classid)
1941f211a1bSDaniel Borkmann {
195143976ceSWANG Cong return clsact_find(sch, classid);
1961f211a1bSDaniel Borkmann }
1971f211a1bSDaniel Borkmann
clsact_tcf_block(struct Qdisc * sch,unsigned long cl,struct netlink_ext_ack * extack)198cbaacc4eSAlexander Aring static struct tcf_block *clsact_tcf_block(struct Qdisc *sch, unsigned long cl,
199cbaacc4eSAlexander Aring struct netlink_ext_ack *extack)
2001f211a1bSDaniel Borkmann {
2016529eabaSJiri Pirko struct clsact_sched_data *q = qdisc_priv(sch);
2021f211a1bSDaniel Borkmann
2031f211a1bSDaniel Borkmann switch (cl) {
2041f211a1bSDaniel Borkmann case TC_H_MIN(TC_H_MIN_INGRESS):
2056529eabaSJiri Pirko return q->ingress_block;
2061f211a1bSDaniel Borkmann case TC_H_MIN(TC_H_MIN_EGRESS):
2076529eabaSJiri Pirko return q->egress_block;
2081f211a1bSDaniel Borkmann default:
2091f211a1bSDaniel Borkmann return NULL;
2101f211a1bSDaniel Borkmann }
2111f211a1bSDaniel Borkmann }
2121f211a1bSDaniel Borkmann
clsact_ingress_block_set(struct Qdisc * sch,u32 block_index)21351ab2994SJiri Pirko static void clsact_ingress_block_set(struct Qdisc *sch, u32 block_index)
21451ab2994SJiri Pirko {
21551ab2994SJiri Pirko struct clsact_sched_data *q = qdisc_priv(sch);
21651ab2994SJiri Pirko
21751ab2994SJiri Pirko q->ingress_block_info.block_index = block_index;
21851ab2994SJiri Pirko }
21951ab2994SJiri Pirko
clsact_egress_block_set(struct Qdisc * sch,u32 block_index)22051ab2994SJiri Pirko static void clsact_egress_block_set(struct Qdisc *sch, u32 block_index)
22151ab2994SJiri Pirko {
22251ab2994SJiri Pirko struct clsact_sched_data *q = qdisc_priv(sch);
22351ab2994SJiri Pirko
22451ab2994SJiri Pirko q->egress_block_info.block_index = block_index;
22551ab2994SJiri Pirko }
22651ab2994SJiri Pirko
clsact_ingress_block_get(struct Qdisc * sch)22751ab2994SJiri Pirko static u32 clsact_ingress_block_get(struct Qdisc *sch)
22851ab2994SJiri Pirko {
22951ab2994SJiri Pirko struct clsact_sched_data *q = qdisc_priv(sch);
23051ab2994SJiri Pirko
23151ab2994SJiri Pirko return q->ingress_block_info.block_index;
23251ab2994SJiri Pirko }
23351ab2994SJiri Pirko
clsact_egress_block_get(struct Qdisc * sch)23451ab2994SJiri Pirko static u32 clsact_egress_block_get(struct Qdisc *sch)
23551ab2994SJiri Pirko {
23651ab2994SJiri Pirko struct clsact_sched_data *q = qdisc_priv(sch);
23751ab2994SJiri Pirko
23851ab2994SJiri Pirko return q->egress_block_info.block_index;
23951ab2994SJiri Pirko }
24051ab2994SJiri Pirko
clsact_init(struct Qdisc * sch,struct nlattr * opt,struct netlink_ext_ack * extack)241e63d7dfdSAlexander Aring static int clsact_init(struct Qdisc *sch, struct nlattr *opt,
242e63d7dfdSAlexander Aring struct netlink_ext_ack *extack)
2431f211a1bSDaniel Borkmann {
2446529eabaSJiri Pirko struct clsact_sched_data *q = qdisc_priv(sch);
2456529eabaSJiri Pirko struct net_device *dev = qdisc_dev(sch);
246e420bed0SDaniel Borkmann struct bpf_mprog_entry *entry;
247e420bed0SDaniel Borkmann bool created;
2486529eabaSJiri Pirko int err;
2496529eabaSJiri Pirko
2505eeebfe6SPeilin Ye if (sch->parent != TC_H_CLSACT)
2515eeebfe6SPeilin Ye return -EOPNOTSUPP;
2525eeebfe6SPeilin Ye
253b59e6979SJiri Pirko net_inc_ingress_queue();
254b59e6979SJiri Pirko net_inc_egress_queue();
255b59e6979SJiri Pirko
256e420bed0SDaniel Borkmann entry = tcx_entry_fetch_or_create(dev, true, &created);
257e420bed0SDaniel Borkmann if (!entry)
258e420bed0SDaniel Borkmann return -ENOMEM;
259*230bb136SDaniel Borkmann tcx_miniq_inc(entry);
260e420bed0SDaniel Borkmann mini_qdisc_pair_init(&q->miniqp_ingress, sch, &tcx_entry(entry)->miniq);
261e420bed0SDaniel Borkmann if (created)
262e420bed0SDaniel Borkmann tcx_entry_update(dev, entry, true);
26346209401SJiri Pirko
26432f8c409SPablo Neira Ayuso q->ingress_block_info.binder_type = FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS;
265c7eb7d72SJiri Pirko q->ingress_block_info.chain_head_change = clsact_chain_head_change;
26646209401SJiri Pirko q->ingress_block_info.chain_head_change_priv = &q->miniqp_ingress;
2676e40cf2dSJiri Pirko
2688d1a77f9SAlexander Aring err = tcf_block_get_ext(&q->ingress_block, sch, &q->ingress_block_info,
2698d1a77f9SAlexander Aring extack);
2706529eabaSJiri Pirko if (err)
2716529eabaSJiri Pirko return err;
2726529eabaSJiri Pirko
2737d17c544SPaul Blakey mini_qdisc_pair_block_init(&q->miniqp_ingress, q->ingress_block);
2747d17c544SPaul Blakey
275e420bed0SDaniel Borkmann entry = tcx_entry_fetch_or_create(dev, false, &created);
276e420bed0SDaniel Borkmann if (!entry)
277e420bed0SDaniel Borkmann return -ENOMEM;
278*230bb136SDaniel Borkmann tcx_miniq_inc(entry);
279e420bed0SDaniel Borkmann mini_qdisc_pair_init(&q->miniqp_egress, sch, &tcx_entry(entry)->miniq);
280e420bed0SDaniel Borkmann if (created)
281e420bed0SDaniel Borkmann tcx_entry_update(dev, entry, false);
28246209401SJiri Pirko
28332f8c409SPablo Neira Ayuso q->egress_block_info.binder_type = FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS;
284c7eb7d72SJiri Pirko q->egress_block_info.chain_head_change = clsact_chain_head_change;
28546209401SJiri Pirko q->egress_block_info.chain_head_change_priv = &q->miniqp_egress;
2866e40cf2dSJiri Pirko
287c02b3741SDavid S. Miller return tcf_block_get_ext(&q->egress_block, sch, &q->egress_block_info, extack);
2881f211a1bSDaniel Borkmann }
2891f211a1bSDaniel Borkmann
clsact_destroy(struct Qdisc * sch)2901f211a1bSDaniel Borkmann static void clsact_destroy(struct Qdisc *sch)
2911f211a1bSDaniel Borkmann {
2926529eabaSJiri Pirko struct clsact_sched_data *q = qdisc_priv(sch);
293e420bed0SDaniel Borkmann struct net_device *dev = qdisc_dev(sch);
294e420bed0SDaniel Borkmann struct bpf_mprog_entry *ingress_entry = rtnl_dereference(dev->tcx_ingress);
295e420bed0SDaniel Borkmann struct bpf_mprog_entry *egress_entry = rtnl_dereference(dev->tcx_egress);
2961f211a1bSDaniel Borkmann
2975eeebfe6SPeilin Ye if (sch->parent != TC_H_CLSACT)
2985eeebfe6SPeilin Ye return;
2995eeebfe6SPeilin Ye
300c7eb7d72SJiri Pirko tcf_block_put_ext(q->ingress_block, sch, &q->ingress_block_info);
301e420bed0SDaniel Borkmann tcf_block_put_ext(q->egress_block, sch, &q->egress_block_info);
302e420bed0SDaniel Borkmann
303e420bed0SDaniel Borkmann if (ingress_entry) {
304*230bb136SDaniel Borkmann tcx_miniq_dec(ingress_entry);
305e420bed0SDaniel Borkmann if (!tcx_entry_is_active(ingress_entry)) {
306e420bed0SDaniel Borkmann tcx_entry_update(dev, NULL, true);
307e420bed0SDaniel Borkmann tcx_entry_free(ingress_entry);
308e420bed0SDaniel Borkmann }
309e420bed0SDaniel Borkmann }
310e420bed0SDaniel Borkmann
311e420bed0SDaniel Borkmann if (egress_entry) {
312*230bb136SDaniel Borkmann tcx_miniq_dec(egress_entry);
313e420bed0SDaniel Borkmann if (!tcx_entry_is_active(egress_entry)) {
314e420bed0SDaniel Borkmann tcx_entry_update(dev, NULL, false);
315e420bed0SDaniel Borkmann tcx_entry_free(egress_entry);
316e420bed0SDaniel Borkmann }
317e420bed0SDaniel Borkmann }
3181f211a1bSDaniel Borkmann
3191f211a1bSDaniel Borkmann net_dec_ingress_queue();
3201f211a1bSDaniel Borkmann net_dec_egress_queue();
3211f211a1bSDaniel Borkmann }
3221f211a1bSDaniel Borkmann
3231f211a1bSDaniel Borkmann static const struct Qdisc_class_ops clsact_class_ops = {
32487f37392SVlad Buslov .flags = QDISC_CLASS_OPS_DOIT_UNLOCKED,
3251f211a1bSDaniel Borkmann .leaf = ingress_leaf,
326143976ceSWANG Cong .find = clsact_find,
3271f211a1bSDaniel Borkmann .walk = ingress_walk,
3286529eabaSJiri Pirko .tcf_block = clsact_tcf_block,
3291f211a1bSDaniel Borkmann .bind_tcf = clsact_bind_filter,
330143976ceSWANG Cong .unbind_tcf = ingress_unbind_filter,
3311f211a1bSDaniel Borkmann };
3321f211a1bSDaniel Borkmann
3331f211a1bSDaniel Borkmann static struct Qdisc_ops clsact_qdisc_ops __read_mostly = {
3341f211a1bSDaniel Borkmann .cl_ops = &clsact_class_ops,
3351f211a1bSDaniel Borkmann .id = "clsact",
3366529eabaSJiri Pirko .priv_size = sizeof(struct clsact_sched_data),
337f85fa45dSPeilin Ye .static_flags = TCQ_F_INGRESS | TCQ_F_CPUSTATS,
3381f211a1bSDaniel Borkmann .init = clsact_init,
3391f211a1bSDaniel Borkmann .destroy = clsact_destroy,
3401f211a1bSDaniel Borkmann .dump = ingress_dump,
34151ab2994SJiri Pirko .ingress_block_set = clsact_ingress_block_set,
34251ab2994SJiri Pirko .egress_block_set = clsact_egress_block_set,
34351ab2994SJiri Pirko .ingress_block_get = clsact_ingress_block_get,
34451ab2994SJiri Pirko .egress_block_get = clsact_egress_block_get,
3451f211a1bSDaniel Borkmann .owner = THIS_MODULE,
3461f211a1bSDaniel Borkmann };
3471f211a1bSDaniel Borkmann
ingress_module_init(void)3481da177e4SLinus Torvalds static int __init ingress_module_init(void)
3491da177e4SLinus Torvalds {
3501f211a1bSDaniel Borkmann int ret;
3511f211a1bSDaniel Borkmann
3521f211a1bSDaniel Borkmann ret = register_qdisc(&ingress_qdisc_ops);
3531f211a1bSDaniel Borkmann if (!ret) {
3541f211a1bSDaniel Borkmann ret = register_qdisc(&clsact_qdisc_ops);
3551f211a1bSDaniel Borkmann if (ret)
3561f211a1bSDaniel Borkmann unregister_qdisc(&ingress_qdisc_ops);
3571f211a1bSDaniel Borkmann }
3581f211a1bSDaniel Borkmann
3591f211a1bSDaniel Borkmann return ret;
3601da177e4SLinus Torvalds }
36158f4df42SPatrick McHardy
ingress_module_exit(void)3621da177e4SLinus Torvalds static void __exit ingress_module_exit(void)
3631da177e4SLinus Torvalds {
3641da177e4SLinus Torvalds unregister_qdisc(&ingress_qdisc_ops);
3651f211a1bSDaniel Borkmann unregister_qdisc(&clsact_qdisc_ops);
3661da177e4SLinus Torvalds }
36758f4df42SPatrick McHardy
368d2788d34SDaniel Borkmann module_init(ingress_module_init);
369d2788d34SDaniel Borkmann module_exit(ingress_module_exit);
370d2788d34SDaniel Borkmann
3711f211a1bSDaniel Borkmann MODULE_ALIAS("sch_clsact");
3721da177e4SLinus Torvalds MODULE_LICENSE("GPL");
373