File Index
Files and directories
Sign in
FILE

sch_ingress.c

File preview with syntax highlighting.

linux-6.19.14/net/sched/sch_ingress.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/* net/sched/sch_ingress.c - Ingress and clsact qdisc
  3 *
  4 * Authors:     Jamal Hadi Salim 1999
  5 */
  6
  7#include <linux/module.h>
  8#include <linux/types.h>
  9#include <linux/list.h>
 10#include <linux/skbuff.h>
 11#include <linux/rtnetlink.h>
 12
 13#include <net/netlink.h>
 14#include <net/pkt_sched.h>
 15#include <net/pkt_cls.h>
 16#include <net/tcx.h>
 17
 18struct ingress_sched_data {
 19	struct tcf_block *block;
 20	struct tcf_block_ext_info block_info;
 21	struct mini_Qdisc_pair miniqp;
 22};
 23
 24static struct Qdisc *ingress_leaf(struct Qdisc *sch, unsigned long arg)
 25{
 26	return NULL;
 27}
 28
 29static unsigned long ingress_find(struct Qdisc *sch, u32 classid)
 30{
 31	return TC_H_MIN(classid) + 1;
 32}
 33
 34static unsigned long ingress_bind_filter(struct Qdisc *sch,
 35					 unsigned long parent, u32 classid)
 36{
 37	return ingress_find(sch, classid);
 38}
 39
 40static void ingress_unbind_filter(struct Qdisc *sch, unsigned long cl)
 41{
 42}
 43
 44static void ingress_walk(struct Qdisc *sch, struct qdisc_walker *walker)
 45{
 46}
 47
 48static struct tcf_block *ingress_tcf_block(struct Qdisc *sch, unsigned long cl,
 49					   struct netlink_ext_ack *extack)
 50{
 51	struct ingress_sched_data *q = qdisc_priv(sch);
 52
 53	return q->block;
 54}
 55
 56static void clsact_chain_head_change(struct tcf_proto *tp_head, void *priv)
 57{
 58	struct mini_Qdisc_pair *miniqp = priv;
 59
 60	mini_qdisc_pair_swap(miniqp, tp_head);
 61};
 62
 63static void ingress_ingress_block_set(struct Qdisc *sch, u32 block_index)
 64{
 65	struct ingress_sched_data *q = qdisc_priv(sch);
 66
 67	q->block_info.block_index = block_index;
 68}
 69
 70static u32 ingress_ingress_block_get(struct Qdisc *sch)
 71{
 72	struct ingress_sched_data *q = qdisc_priv(sch);
 73
 74	return q->block_info.block_index;
 75}
 76
 77static int ingress_init(struct Qdisc *sch, struct nlattr *opt,
 78			struct netlink_ext_ack *extack)
 79{
 80	struct ingress_sched_data *q = qdisc_priv(sch);
 81	struct net_device *dev = qdisc_dev(sch);
 82	struct bpf_mprog_entry *entry;
 83	bool created;
 84	int err;
 85
 86	if (sch->parent != TC_H_INGRESS)
 87		return -EOPNOTSUPP;
 88
 89	net_inc_ingress_queue();
 90
 91	entry = tcx_entry_fetch_or_create(dev, true, &created);
 92	if (!entry)
 93		return -ENOMEM;
 94	tcx_miniq_inc(entry);
 95	mini_qdisc_pair_init(&q->miniqp, sch, &tcx_entry(entry)->miniq);
 96	if (created)
 97		tcx_entry_update(dev, entry, true);
 98
 99	q->block_info.binder_type = FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS;
100	q->block_info.chain_head_change = clsact_chain_head_change;
101	q->block_info.chain_head_change_priv = &q->miniqp;
102
103	err = tcf_block_get_ext(&q->block, sch, &q->block_info, extack);
104	if (err)
105		return err;
106
107	mini_qdisc_pair_block_init(&q->miniqp, q->block);
108
109	return 0;
110}
111
112static void ingress_destroy(struct Qdisc *sch)
113{
114	struct ingress_sched_data *q = qdisc_priv(sch);
115	struct net_device *dev = qdisc_dev(sch);
116	struct bpf_mprog_entry *entry;
117
118	if (sch->parent != TC_H_INGRESS)
119		return;
120
121	tcf_block_put_ext(q->block, sch, &q->block_info);
122
123	if (mini_qdisc_pair_inited(&q->miniqp)) {
124		entry = rtnl_dereference(dev->tcx_ingress);
125		tcx_miniq_dec(entry);
126		if (!tcx_entry_is_active(entry)) {
127			tcx_entry_update(dev, NULL, true);
128			tcx_entry_free(entry);
129		}
130	}
131
132	net_dec_ingress_queue();
133}
134
135static int ingress_dump(struct Qdisc *sch, struct sk_buff *skb)
136{
137	struct nlattr *nest;
138
139	nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
140	if (nest == NULL)
141		goto nla_put_failure;
142
143	return nla_nest_end(skb, nest);
144
145nla_put_failure:
146	nla_nest_cancel(skb, nest);
147	return -1;
148}
149
150static const struct Qdisc_class_ops ingress_class_ops = {
151	.flags		=	QDISC_CLASS_OPS_DOIT_UNLOCKED,
152	.leaf		=	ingress_leaf,
153	.find		=	ingress_find,
154	.walk		=	ingress_walk,
155	.tcf_block	=	ingress_tcf_block,
156	.bind_tcf	=	ingress_bind_filter,
157	.unbind_tcf	=	ingress_unbind_filter,
158};
159
160static struct Qdisc_ops ingress_qdisc_ops __read_mostly = {
161	.cl_ops			=	&ingress_class_ops,
162	.id			=	"ingress",
163	.priv_size		=	sizeof(struct ingress_sched_data),
164	.static_flags		=	TCQ_F_INGRESS | TCQ_F_CPUSTATS,
165	.init			=	ingress_init,
166	.destroy		=	ingress_destroy,
167	.dump			=	ingress_dump,
168	.ingress_block_set	=	ingress_ingress_block_set,
169	.ingress_block_get	=	ingress_ingress_block_get,
170	.owner			=	THIS_MODULE,
171};
172MODULE_ALIAS_NET_SCH("ingress");
173
174struct clsact_sched_data {
175	struct tcf_block *ingress_block;
176	struct tcf_block *egress_block;
177	struct tcf_block_ext_info ingress_block_info;
178	struct tcf_block_ext_info egress_block_info;
179	struct mini_Qdisc_pair miniqp_ingress;
180	struct mini_Qdisc_pair miniqp_egress;
181};
182
183static unsigned long clsact_find(struct Qdisc *sch, u32 classid)
184{
185	switch (TC_H_MIN(classid)) {
186	case TC_H_MIN(TC_H_MIN_INGRESS):
187	case TC_H_MIN(TC_H_MIN_EGRESS):
188		return TC_H_MIN(classid);
189	default:
190		return 0;
191	}
192}
193
194static unsigned long clsact_bind_filter(struct Qdisc *sch,
195					unsigned long parent, u32 classid)
196{
197	return clsact_find(sch, classid);
198}
199
200static struct tcf_block *clsact_tcf_block(struct Qdisc *sch, unsigned long cl,
201					  struct netlink_ext_ack *extack)
202{
203	struct clsact_sched_data *q = qdisc_priv(sch);
204
205	switch (cl) {
206	case TC_H_MIN(TC_H_MIN_INGRESS):
207		return q->ingress_block;
208	case TC_H_MIN(TC_H_MIN_EGRESS):
209		return q->egress_block;
210	default:
211		return NULL;
212	}
213}
214
215static void clsact_ingress_block_set(struct Qdisc *sch, u32 block_index)
216{
217	struct clsact_sched_data *q = qdisc_priv(sch);
218
219	q->ingress_block_info.block_index = block_index;
220}
221
222static void clsact_egress_block_set(struct Qdisc *sch, u32 block_index)
223{
224	struct clsact_sched_data *q = qdisc_priv(sch);
225
226	q->egress_block_info.block_index = block_index;
227}
228
229static u32 clsact_ingress_block_get(struct Qdisc *sch)
230{
231	struct clsact_sched_data *q = qdisc_priv(sch);
232
233	return q->ingress_block_info.block_index;
234}
235
236static u32 clsact_egress_block_get(struct Qdisc *sch)
237{
238	struct clsact_sched_data *q = qdisc_priv(sch);
239
240	return q->egress_block_info.block_index;
241}
242
243static int clsact_init(struct Qdisc *sch, struct nlattr *opt,
244		       struct netlink_ext_ack *extack)
245{
246	struct clsact_sched_data *q = qdisc_priv(sch);
247	struct net_device *dev = qdisc_dev(sch);
248	struct bpf_mprog_entry *entry;
249	bool created;
250	int err;
251
252	if (sch->parent != TC_H_CLSACT)
253		return -EOPNOTSUPP;
254
255	net_inc_ingress_queue();
256	net_inc_egress_queue();
257
258	entry = tcx_entry_fetch_or_create(dev, true, &created);
259	if (!entry)
260		return -ENOMEM;
261	tcx_miniq_inc(entry);
262	mini_qdisc_pair_init(&q->miniqp_ingress, sch, &tcx_entry(entry)->miniq);
263	if (created)
264		tcx_entry_update(dev, entry, true);
265
266	q->ingress_block_info.binder_type = FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS;
267	q->ingress_block_info.chain_head_change = clsact_chain_head_change;
268	q->ingress_block_info.chain_head_change_priv = &q->miniqp_ingress;
269
270	err = tcf_block_get_ext(&q->ingress_block, sch, &q->ingress_block_info,
271				extack);
272	if (err)
273		return err;
274
275	mini_qdisc_pair_block_init(&q->miniqp_ingress, q->ingress_block);
276
277	entry = tcx_entry_fetch_or_create(dev, false, &created);
278	if (!entry)
279		return -ENOMEM;
280	tcx_miniq_inc(entry);
281	mini_qdisc_pair_init(&q->miniqp_egress, sch, &tcx_entry(entry)->miniq);
282	if (created)
283		tcx_entry_update(dev, entry, false);
284
285	q->egress_block_info.binder_type = FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS;
286	q->egress_block_info.chain_head_change = clsact_chain_head_change;
287	q->egress_block_info.chain_head_change_priv = &q->miniqp_egress;
288
289	return tcf_block_get_ext(&q->egress_block, sch, &q->egress_block_info, extack);
290}
291
292static void clsact_destroy(struct Qdisc *sch)
293{
294	struct bpf_mprog_entry *ingress_entry, *egress_entry;
295	struct clsact_sched_data *q = qdisc_priv(sch);
296	struct net_device *dev = qdisc_dev(sch);
297
298	if (sch->parent != TC_H_CLSACT)
299		return;
300
301	tcf_block_put_ext(q->ingress_block, sch, &q->ingress_block_info);
302	tcf_block_put_ext(q->egress_block, sch, &q->egress_block_info);
303
304	if (mini_qdisc_pair_inited(&q->miniqp_ingress)) {
305		ingress_entry = rtnl_dereference(dev->tcx_ingress);
306		tcx_miniq_dec(ingress_entry);
307		if (!tcx_entry_is_active(ingress_entry)) {
308			tcx_entry_update(dev, NULL, true);
309			tcx_entry_free(ingress_entry);
310		}
311	}
312
313	if (mini_qdisc_pair_inited(&q->miniqp_egress)) {
314		egress_entry = rtnl_dereference(dev->tcx_egress);
315		tcx_miniq_dec(egress_entry);
316		if (!tcx_entry_is_active(egress_entry)) {
317			tcx_entry_update(dev, NULL, false);
318			tcx_entry_free(egress_entry);
319		}
320	}
321
322	net_dec_ingress_queue();
323	net_dec_egress_queue();
324}
325
326static const struct Qdisc_class_ops clsact_class_ops = {
327	.flags		=	QDISC_CLASS_OPS_DOIT_UNLOCKED,
328	.leaf		=	ingress_leaf,
329	.find		=	clsact_find,
330	.walk		=	ingress_walk,
331	.tcf_block	=	clsact_tcf_block,
332	.bind_tcf	=	clsact_bind_filter,
333	.unbind_tcf	=	ingress_unbind_filter,
334};
335
336static struct Qdisc_ops clsact_qdisc_ops __read_mostly = {
337	.cl_ops			=	&clsact_class_ops,
338	.id			=	"clsact",
339	.priv_size		=	sizeof(struct clsact_sched_data),
340	.static_flags		=	TCQ_F_INGRESS | TCQ_F_CPUSTATS,
341	.init			=	clsact_init,
342	.destroy		=	clsact_destroy,
343	.dump			=	ingress_dump,
344	.ingress_block_set	=	clsact_ingress_block_set,
345	.egress_block_set	=	clsact_egress_block_set,
346	.ingress_block_get	=	clsact_ingress_block_get,
347	.egress_block_get	=	clsact_egress_block_get,
348	.owner			=	THIS_MODULE,
349};
350MODULE_ALIAS_NET_SCH("clsact");
351
352static int __init ingress_module_init(void)
353{
354	int ret;
355
356	ret = register_qdisc(&ingress_qdisc_ops);
357	if (!ret) {
358		ret = register_qdisc(&clsact_qdisc_ops);
359		if (ret)
360			unregister_qdisc(&ingress_qdisc_ops);
361	}
362
363	return ret;
364}
365
366static void __exit ingress_module_exit(void)
367{
368	unregister_qdisc(&ingress_qdisc_ops);
369	unregister_qdisc(&clsact_qdisc_ops);
370}
371
372module_init(ingress_module_init);
373module_exit(ingress_module_exit);
374
375MODULE_LICENSE("GPL");
376MODULE_DESCRIPTION("Ingress and clsact based ingress and egress qdiscs");
~/ Read-only file preview.