xref: /kernel/linux/linux-6.6/include/net/tcx.h (revision 62306a36)
1/* SPDX-License-Identifier: GPL-2.0 */
2/* Copyright (c) 2023 Isovalent */
3#ifndef __NET_TCX_H
4#define __NET_TCX_H
5
6#include <linux/bpf.h>
7#include <linux/bpf_mprog.h>
8
9#include <net/sch_generic.h>
10
11struct mini_Qdisc;
12
13struct tcx_entry {
14	struct mini_Qdisc __rcu *miniq;
15	struct bpf_mprog_bundle bundle;
16	bool miniq_active;
17	struct rcu_head rcu;
18};
19
20struct tcx_link {
21	struct bpf_link link;
22	struct net_device *dev;
23	u32 location;
24};
25
26static inline void tcx_set_ingress(struct sk_buff *skb, bool ingress)
27{
28#ifdef CONFIG_NET_XGRESS
29	skb->tc_at_ingress = ingress;
30#endif
31}
32
33#ifdef CONFIG_NET_XGRESS
34static inline struct tcx_entry *tcx_entry(struct bpf_mprog_entry *entry)
35{
36	struct bpf_mprog_bundle *bundle = entry->parent;
37
38	return container_of(bundle, struct tcx_entry, bundle);
39}
40
41static inline struct tcx_link *tcx_link(struct bpf_link *link)
42{
43	return container_of(link, struct tcx_link, link);
44}
45
46static inline const struct tcx_link *tcx_link_const(const struct bpf_link *link)
47{
48	return tcx_link((struct bpf_link *)link);
49}
50
51void tcx_inc(void);
52void tcx_dec(void);
53
54static inline void tcx_entry_sync(void)
55{
56	/* bpf_mprog_entry got a/b swapped, therefore ensure that
57	 * there are no inflight users on the old one anymore.
58	 */
59	synchronize_rcu();
60}
61
62static inline void
63tcx_entry_update(struct net_device *dev, struct bpf_mprog_entry *entry,
64		 bool ingress)
65{
66	ASSERT_RTNL();
67	if (ingress)
68		rcu_assign_pointer(dev->tcx_ingress, entry);
69	else
70		rcu_assign_pointer(dev->tcx_egress, entry);
71}
72
73static inline struct bpf_mprog_entry *
74tcx_entry_fetch(struct net_device *dev, bool ingress)
75{
76	ASSERT_RTNL();
77	if (ingress)
78		return rcu_dereference_rtnl(dev->tcx_ingress);
79	else
80		return rcu_dereference_rtnl(dev->tcx_egress);
81}
82
83static inline struct bpf_mprog_entry *tcx_entry_create(void)
84{
85	struct tcx_entry *tcx = kzalloc(sizeof(*tcx), GFP_KERNEL);
86
87	if (tcx) {
88		bpf_mprog_bundle_init(&tcx->bundle);
89		return &tcx->bundle.a;
90	}
91	return NULL;
92}
93
94static inline void tcx_entry_free(struct bpf_mprog_entry *entry)
95{
96	kfree_rcu(tcx_entry(entry), rcu);
97}
98
99static inline struct bpf_mprog_entry *
100tcx_entry_fetch_or_create(struct net_device *dev, bool ingress, bool *created)
101{
102	struct bpf_mprog_entry *entry = tcx_entry_fetch(dev, ingress);
103
104	*created = false;
105	if (!entry) {
106		entry = tcx_entry_create();
107		if (!entry)
108			return NULL;
109		*created = true;
110	}
111	return entry;
112}
113
114static inline void tcx_skeys_inc(bool ingress)
115{
116	tcx_inc();
117	if (ingress)
118		net_inc_ingress_queue();
119	else
120		net_inc_egress_queue();
121}
122
123static inline void tcx_skeys_dec(bool ingress)
124{
125	if (ingress)
126		net_dec_ingress_queue();
127	else
128		net_dec_egress_queue();
129	tcx_dec();
130}
131
132static inline void tcx_miniq_set_active(struct bpf_mprog_entry *entry,
133					const bool active)
134{
135	ASSERT_RTNL();
136	tcx_entry(entry)->miniq_active = active;
137}
138
139static inline bool tcx_entry_is_active(struct bpf_mprog_entry *entry)
140{
141	ASSERT_RTNL();
142	return bpf_mprog_total(entry) || tcx_entry(entry)->miniq_active;
143}
144
145static inline enum tcx_action_base tcx_action_code(struct sk_buff *skb,
146						   int code)
147{
148	switch (code) {
149	case TCX_PASS:
150		skb->tc_index = qdisc_skb_cb(skb)->tc_classid;
151		fallthrough;
152	case TCX_DROP:
153	case TCX_REDIRECT:
154		return code;
155	case TCX_NEXT:
156	default:
157		return TCX_NEXT;
158	}
159}
160#endif /* CONFIG_NET_XGRESS */
161
162#if defined(CONFIG_NET_XGRESS) && defined(CONFIG_BPF_SYSCALL)
163int tcx_prog_attach(const union bpf_attr *attr, struct bpf_prog *prog);
164int tcx_link_attach(const union bpf_attr *attr, struct bpf_prog *prog);
165int tcx_prog_detach(const union bpf_attr *attr, struct bpf_prog *prog);
166void tcx_uninstall(struct net_device *dev, bool ingress);
167
168int tcx_prog_query(const union bpf_attr *attr,
169		   union bpf_attr __user *uattr);
170
171static inline void dev_tcx_uninstall(struct net_device *dev)
172{
173	ASSERT_RTNL();
174	tcx_uninstall(dev, true);
175	tcx_uninstall(dev, false);
176}
177#else
178static inline int tcx_prog_attach(const union bpf_attr *attr,
179				  struct bpf_prog *prog)
180{
181	return -EINVAL;
182}
183
184static inline int tcx_link_attach(const union bpf_attr *attr,
185				  struct bpf_prog *prog)
186{
187	return -EINVAL;
188}
189
190static inline int tcx_prog_detach(const union bpf_attr *attr,
191				  struct bpf_prog *prog)
192{
193	return -EINVAL;
194}
195
196static inline int tcx_prog_query(const union bpf_attr *attr,
197				 union bpf_attr __user *uattr)
198{
199	return -EINVAL;
200}
201
202static inline void dev_tcx_uninstall(struct net_device *dev)
203{
204}
205#endif /* CONFIG_NET_XGRESS && CONFIG_BPF_SYSCALL */
206#endif /* __NET_TCX_H */
207