xref: /openbmc/linux/net/sched/sch_ingress.c (revision 6e4f6b5eac461867471b3f368699097b31843d23)
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