Merge tag 'regulator-fix-v5.3-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / net / core / flow_offload.c
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #include <linux/kernel.h>
3 #include <linux/slab.h>
4 #include <net/flow_offload.h>
5
6 struct flow_rule *flow_rule_alloc(unsigned int num_actions)
7 {
8         struct flow_rule *rule;
9
10         rule = kzalloc(struct_size(rule, action.entries, num_actions),
11                        GFP_KERNEL);
12         if (!rule)
13                 return NULL;
14
15         rule->action.num_entries = num_actions;
16
17         return rule;
18 }
19 EXPORT_SYMBOL(flow_rule_alloc);
20
21 #define FLOW_DISSECTOR_MATCH(__rule, __type, __out)                             \
22         const struct flow_match *__m = &(__rule)->match;                        \
23         struct flow_dissector *__d = (__m)->dissector;                          \
24                                                                                 \
25         (__out)->key = skb_flow_dissector_target(__d, __type, (__m)->key);      \
26         (__out)->mask = skb_flow_dissector_target(__d, __type, (__m)->mask);    \
27
28 void flow_rule_match_meta(const struct flow_rule *rule,
29                           struct flow_match_meta *out)
30 {
31         FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_META, out);
32 }
33 EXPORT_SYMBOL(flow_rule_match_meta);
34
35 void flow_rule_match_basic(const struct flow_rule *rule,
36                            struct flow_match_basic *out)
37 {
38         FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_BASIC, out);
39 }
40 EXPORT_SYMBOL(flow_rule_match_basic);
41
42 void flow_rule_match_control(const struct flow_rule *rule,
43                              struct flow_match_control *out)
44 {
45         FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_CONTROL, out);
46 }
47 EXPORT_SYMBOL(flow_rule_match_control);
48
49 void flow_rule_match_eth_addrs(const struct flow_rule *rule,
50                                struct flow_match_eth_addrs *out)
51 {
52         FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS, out);
53 }
54 EXPORT_SYMBOL(flow_rule_match_eth_addrs);
55
56 void flow_rule_match_vlan(const struct flow_rule *rule,
57                           struct flow_match_vlan *out)
58 {
59         FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_VLAN, out);
60 }
61 EXPORT_SYMBOL(flow_rule_match_vlan);
62
63 void flow_rule_match_cvlan(const struct flow_rule *rule,
64                            struct flow_match_vlan *out)
65 {
66         FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_CVLAN, out);
67 }
68 EXPORT_SYMBOL(flow_rule_match_cvlan);
69
70 void flow_rule_match_ipv4_addrs(const struct flow_rule *rule,
71                                 struct flow_match_ipv4_addrs *out)
72 {
73         FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS, out);
74 }
75 EXPORT_SYMBOL(flow_rule_match_ipv4_addrs);
76
77 void flow_rule_match_ipv6_addrs(const struct flow_rule *rule,
78                                 struct flow_match_ipv6_addrs *out)
79 {
80         FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS, out);
81 }
82 EXPORT_SYMBOL(flow_rule_match_ipv6_addrs);
83
84 void flow_rule_match_ip(const struct flow_rule *rule,
85                         struct flow_match_ip *out)
86 {
87         FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_IP, out);
88 }
89 EXPORT_SYMBOL(flow_rule_match_ip);
90
91 void flow_rule_match_ports(const struct flow_rule *rule,
92                            struct flow_match_ports *out)
93 {
94         FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_PORTS, out);
95 }
96 EXPORT_SYMBOL(flow_rule_match_ports);
97
98 void flow_rule_match_tcp(const struct flow_rule *rule,
99                          struct flow_match_tcp *out)
100 {
101         FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_TCP, out);
102 }
103 EXPORT_SYMBOL(flow_rule_match_tcp);
104
105 void flow_rule_match_icmp(const struct flow_rule *rule,
106                           struct flow_match_icmp *out)
107 {
108         FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ICMP, out);
109 }
110 EXPORT_SYMBOL(flow_rule_match_icmp);
111
112 void flow_rule_match_mpls(const struct flow_rule *rule,
113                           struct flow_match_mpls *out)
114 {
115         FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_MPLS, out);
116 }
117 EXPORT_SYMBOL(flow_rule_match_mpls);
118
119 void flow_rule_match_enc_control(const struct flow_rule *rule,
120                                  struct flow_match_control *out)
121 {
122         FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_CONTROL, out);
123 }
124 EXPORT_SYMBOL(flow_rule_match_enc_control);
125
126 void flow_rule_match_enc_ipv4_addrs(const struct flow_rule *rule,
127                                     struct flow_match_ipv4_addrs *out)
128 {
129         FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, out);
130 }
131 EXPORT_SYMBOL(flow_rule_match_enc_ipv4_addrs);
132
133 void flow_rule_match_enc_ipv6_addrs(const struct flow_rule *rule,
134                                     struct flow_match_ipv6_addrs *out)
135 {
136         FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS, out);
137 }
138 EXPORT_SYMBOL(flow_rule_match_enc_ipv6_addrs);
139
140 void flow_rule_match_enc_ip(const struct flow_rule *rule,
141                             struct flow_match_ip *out)
142 {
143         FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_IP, out);
144 }
145 EXPORT_SYMBOL(flow_rule_match_enc_ip);
146
147 void flow_rule_match_enc_ports(const struct flow_rule *rule,
148                                struct flow_match_ports *out)
149 {
150         FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_PORTS, out);
151 }
152 EXPORT_SYMBOL(flow_rule_match_enc_ports);
153
154 void flow_rule_match_enc_keyid(const struct flow_rule *rule,
155                                struct flow_match_enc_keyid *out)
156 {
157         FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_KEYID, out);
158 }
159 EXPORT_SYMBOL(flow_rule_match_enc_keyid);
160
161 void flow_rule_match_enc_opts(const struct flow_rule *rule,
162                               struct flow_match_enc_opts *out)
163 {
164         FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_OPTS, out);
165 }
166 EXPORT_SYMBOL(flow_rule_match_enc_opts);
167
168 struct flow_block_cb *flow_block_cb_alloc(flow_setup_cb_t *cb,
169                                           void *cb_ident, void *cb_priv,
170                                           void (*release)(void *cb_priv))
171 {
172         struct flow_block_cb *block_cb;
173
174         block_cb = kzalloc(sizeof(*block_cb), GFP_KERNEL);
175         if (!block_cb)
176                 return ERR_PTR(-ENOMEM);
177
178         block_cb->cb = cb;
179         block_cb->cb_ident = cb_ident;
180         block_cb->cb_priv = cb_priv;
181         block_cb->release = release;
182
183         return block_cb;
184 }
185 EXPORT_SYMBOL(flow_block_cb_alloc);
186
187 void flow_block_cb_free(struct flow_block_cb *block_cb)
188 {
189         if (block_cb->release)
190                 block_cb->release(block_cb->cb_priv);
191
192         kfree(block_cb);
193 }
194 EXPORT_SYMBOL(flow_block_cb_free);
195
196 struct flow_block_cb *flow_block_cb_lookup(struct flow_block *block,
197                                            flow_setup_cb_t *cb, void *cb_ident)
198 {
199         struct flow_block_cb *block_cb;
200
201         list_for_each_entry(block_cb, &block->cb_list, list) {
202                 if (block_cb->cb == cb &&
203                     block_cb->cb_ident == cb_ident)
204                         return block_cb;
205         }
206
207         return NULL;
208 }
209 EXPORT_SYMBOL(flow_block_cb_lookup);
210
211 void *flow_block_cb_priv(struct flow_block_cb *block_cb)
212 {
213         return block_cb->cb_priv;
214 }
215 EXPORT_SYMBOL(flow_block_cb_priv);
216
217 void flow_block_cb_incref(struct flow_block_cb *block_cb)
218 {
219         block_cb->refcnt++;
220 }
221 EXPORT_SYMBOL(flow_block_cb_incref);
222
223 unsigned int flow_block_cb_decref(struct flow_block_cb *block_cb)
224 {
225         return --block_cb->refcnt;
226 }
227 EXPORT_SYMBOL(flow_block_cb_decref);
228
229 bool flow_block_cb_is_busy(flow_setup_cb_t *cb, void *cb_ident,
230                            struct list_head *driver_block_list)
231 {
232         struct flow_block_cb *block_cb;
233
234         list_for_each_entry(block_cb, driver_block_list, driver_list) {
235                 if (block_cb->cb == cb &&
236                     block_cb->cb_ident == cb_ident)
237                         return true;
238         }
239
240         return false;
241 }
242 EXPORT_SYMBOL(flow_block_cb_is_busy);
243
244 int flow_block_cb_setup_simple(struct flow_block_offload *f,
245                                struct list_head *driver_block_list,
246                                flow_setup_cb_t *cb,
247                                void *cb_ident, void *cb_priv,
248                                bool ingress_only)
249 {
250         struct flow_block_cb *block_cb;
251
252         if (ingress_only &&
253             f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
254                 return -EOPNOTSUPP;
255
256         f->driver_block_list = driver_block_list;
257
258         switch (f->command) {
259         case FLOW_BLOCK_BIND:
260                 if (flow_block_cb_is_busy(cb, cb_ident, driver_block_list))
261                         return -EBUSY;
262
263                 block_cb = flow_block_cb_alloc(cb, cb_ident, cb_priv, NULL);
264                 if (IS_ERR(block_cb))
265                         return PTR_ERR(block_cb);
266
267                 flow_block_cb_add(block_cb, f);
268                 list_add_tail(&block_cb->driver_list, driver_block_list);
269                 return 0;
270         case FLOW_BLOCK_UNBIND:
271                 block_cb = flow_block_cb_lookup(f->block, cb, cb_ident);
272                 if (!block_cb)
273                         return -ENOENT;
274
275                 flow_block_cb_remove(block_cb, f);
276                 list_del(&block_cb->driver_list);
277                 return 0;
278         default:
279                 return -EOPNOTSUPP;
280         }
281 }
282 EXPORT_SYMBOL(flow_block_cb_setup_simple);