]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blob - drivers/net/ethernet/mscc/ocelot_flower.c
net: flow_offload: rename TCF_BLOCK_BINDER_TYPE_* to FLOW_BLOCK_BINDER_TYPE_*
[mirror_ubuntu-hirsute-kernel.git] / drivers / net / ethernet / mscc / ocelot_flower.c
1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
2 /* Microsemi Ocelot Switch driver
3 * Copyright (c) 2019 Microsemi Corporation
4 */
5
6 #include <net/pkt_cls.h>
7 #include <net/tc_act/tc_gact.h>
8
9 #include "ocelot_ace.h"
10
11 struct ocelot_port_block {
12 struct ocelot_acl_block *block;
13 struct ocelot_port *port;
14 };
15
16 static u16 get_prio(u32 prio)
17 {
18 /* prio starts from 0x1000 while the ids starts from 0 */
19 return prio >> 16;
20 }
21
22 static int ocelot_flower_parse_action(struct tc_cls_flower_offload *f,
23 struct ocelot_ace_rule *rule)
24 {
25 const struct flow_action_entry *a;
26 int i;
27
28 if (f->rule->action.num_entries != 1)
29 return -EOPNOTSUPP;
30
31 flow_action_for_each(i, a, &f->rule->action) {
32 switch (a->id) {
33 case FLOW_ACTION_DROP:
34 rule->action = OCELOT_ACL_ACTION_DROP;
35 break;
36 case FLOW_ACTION_TRAP:
37 rule->action = OCELOT_ACL_ACTION_TRAP;
38 break;
39 default:
40 return -EOPNOTSUPP;
41 }
42 }
43
44 return 0;
45 }
46
47 static int ocelot_flower_parse(struct tc_cls_flower_offload *f,
48 struct ocelot_ace_rule *ocelot_rule)
49 {
50 struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
51 struct flow_dissector *dissector = rule->match.dissector;
52
53 if (dissector->used_keys &
54 ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
55 BIT(FLOW_DISSECTOR_KEY_BASIC) |
56 BIT(FLOW_DISSECTOR_KEY_PORTS) |
57 BIT(FLOW_DISSECTOR_KEY_VLAN) |
58 BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
59 BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
60 BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
61 return -EOPNOTSUPP;
62 }
63
64 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
65 struct flow_match_control match;
66
67 flow_rule_match_control(rule, &match);
68 }
69
70 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
71 struct flow_match_eth_addrs match;
72 u16 proto = ntohs(f->common.protocol);
73
74 /* The hw support mac matches only for MAC_ETYPE key,
75 * therefore if other matches(port, tcp flags, etc) are added
76 * then just bail out
77 */
78 if ((dissector->used_keys &
79 (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
80 BIT(FLOW_DISSECTOR_KEY_BASIC) |
81 BIT(FLOW_DISSECTOR_KEY_CONTROL))) !=
82 (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
83 BIT(FLOW_DISSECTOR_KEY_BASIC) |
84 BIT(FLOW_DISSECTOR_KEY_CONTROL)))
85 return -EOPNOTSUPP;
86
87 if (proto == ETH_P_IP ||
88 proto == ETH_P_IPV6 ||
89 proto == ETH_P_ARP)
90 return -EOPNOTSUPP;
91
92 flow_rule_match_eth_addrs(rule, &match);
93 ocelot_rule->type = OCELOT_ACE_TYPE_ETYPE;
94 ether_addr_copy(ocelot_rule->frame.etype.dmac.value,
95 match.key->dst);
96 ether_addr_copy(ocelot_rule->frame.etype.smac.value,
97 match.key->src);
98 ether_addr_copy(ocelot_rule->frame.etype.dmac.mask,
99 match.mask->dst);
100 ether_addr_copy(ocelot_rule->frame.etype.smac.mask,
101 match.mask->src);
102 goto finished_key_parsing;
103 }
104
105 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
106 struct flow_match_basic match;
107
108 flow_rule_match_basic(rule, &match);
109 if (ntohs(match.key->n_proto) == ETH_P_IP) {
110 ocelot_rule->type = OCELOT_ACE_TYPE_IPV4;
111 ocelot_rule->frame.ipv4.proto.value[0] =
112 match.key->ip_proto;
113 ocelot_rule->frame.ipv4.proto.mask[0] =
114 match.mask->ip_proto;
115 }
116 if (ntohs(match.key->n_proto) == ETH_P_IPV6) {
117 ocelot_rule->type = OCELOT_ACE_TYPE_IPV6;
118 ocelot_rule->frame.ipv6.proto.value[0] =
119 match.key->ip_proto;
120 ocelot_rule->frame.ipv6.proto.mask[0] =
121 match.mask->ip_proto;
122 }
123 }
124
125 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS) &&
126 ntohs(f->common.protocol) == ETH_P_IP) {
127 struct flow_match_ipv4_addrs match;
128 u8 *tmp;
129
130 flow_rule_match_ipv4_addrs(rule, &match);
131 tmp = &ocelot_rule->frame.ipv4.sip.value.addr[0];
132 memcpy(tmp, &match.key->src, 4);
133
134 tmp = &ocelot_rule->frame.ipv4.sip.mask.addr[0];
135 memcpy(tmp, &match.mask->src, 4);
136
137 tmp = &ocelot_rule->frame.ipv4.dip.value.addr[0];
138 memcpy(tmp, &match.key->dst, 4);
139
140 tmp = &ocelot_rule->frame.ipv4.dip.mask.addr[0];
141 memcpy(tmp, &match.mask->dst, 4);
142 }
143
144 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS) &&
145 ntohs(f->common.protocol) == ETH_P_IPV6) {
146 return -EOPNOTSUPP;
147 }
148
149 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
150 struct flow_match_ports match;
151
152 flow_rule_match_ports(rule, &match);
153 ocelot_rule->frame.ipv4.sport.value = ntohs(match.key->src);
154 ocelot_rule->frame.ipv4.sport.mask = ntohs(match.mask->src);
155 ocelot_rule->frame.ipv4.dport.value = ntohs(match.key->dst);
156 ocelot_rule->frame.ipv4.dport.mask = ntohs(match.mask->dst);
157 }
158
159 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
160 struct flow_match_vlan match;
161
162 flow_rule_match_vlan(rule, &match);
163 ocelot_rule->type = OCELOT_ACE_TYPE_ANY;
164 ocelot_rule->vlan.vid.value = match.key->vlan_id;
165 ocelot_rule->vlan.vid.mask = match.mask->vlan_id;
166 ocelot_rule->vlan.pcp.value[0] = match.key->vlan_priority;
167 ocelot_rule->vlan.pcp.mask[0] = match.mask->vlan_priority;
168 }
169
170 finished_key_parsing:
171 ocelot_rule->prio = get_prio(f->common.prio);
172 ocelot_rule->id = f->cookie;
173 return ocelot_flower_parse_action(f, ocelot_rule);
174 }
175
176 static
177 struct ocelot_ace_rule *ocelot_ace_rule_create(struct tc_cls_flower_offload *f,
178 struct ocelot_port_block *block)
179 {
180 struct ocelot_ace_rule *rule;
181
182 rule = kzalloc(sizeof(*rule), GFP_KERNEL);
183 if (!rule)
184 return NULL;
185
186 rule->port = block->port;
187 rule->chip_port = block->port->chip_port;
188 return rule;
189 }
190
191 static int ocelot_flower_replace(struct tc_cls_flower_offload *f,
192 struct ocelot_port_block *port_block)
193 {
194 struct ocelot_ace_rule *rule;
195 int ret;
196
197 rule = ocelot_ace_rule_create(f, port_block);
198 if (!rule)
199 return -ENOMEM;
200
201 ret = ocelot_flower_parse(f, rule);
202 if (ret) {
203 kfree(rule);
204 return ret;
205 }
206
207 ret = ocelot_ace_rule_offload_add(rule);
208 if (ret)
209 return ret;
210
211 port_block->port->tc.offload_cnt++;
212 return 0;
213 }
214
215 static int ocelot_flower_destroy(struct tc_cls_flower_offload *f,
216 struct ocelot_port_block *port_block)
217 {
218 struct ocelot_ace_rule rule;
219 int ret;
220
221 rule.prio = get_prio(f->common.prio);
222 rule.port = port_block->port;
223 rule.id = f->cookie;
224
225 ret = ocelot_ace_rule_offload_del(&rule);
226 if (ret)
227 return ret;
228
229 port_block->port->tc.offload_cnt--;
230 return 0;
231 }
232
233 static int ocelot_flower_stats_update(struct tc_cls_flower_offload *f,
234 struct ocelot_port_block *port_block)
235 {
236 struct ocelot_ace_rule rule;
237 int ret;
238
239 rule.prio = get_prio(f->common.prio);
240 rule.port = port_block->port;
241 rule.id = f->cookie;
242 ret = ocelot_ace_rule_stats_update(&rule);
243 if (ret)
244 return ret;
245
246 flow_stats_update(&f->stats, 0x0, rule.stats.pkts, 0x0);
247 return 0;
248 }
249
250 static int ocelot_setup_tc_cls_flower(struct tc_cls_flower_offload *f,
251 struct ocelot_port_block *port_block)
252 {
253 switch (f->command) {
254 case TC_CLSFLOWER_REPLACE:
255 return ocelot_flower_replace(f, port_block);
256 case TC_CLSFLOWER_DESTROY:
257 return ocelot_flower_destroy(f, port_block);
258 case TC_CLSFLOWER_STATS:
259 return ocelot_flower_stats_update(f, port_block);
260 default:
261 return -EOPNOTSUPP;
262 }
263 }
264
265 static int ocelot_setup_tc_block_cb_flower(enum tc_setup_type type,
266 void *type_data, void *cb_priv)
267 {
268 struct ocelot_port_block *port_block = cb_priv;
269
270 if (!tc_cls_can_offload_and_chain0(port_block->port->dev, type_data))
271 return -EOPNOTSUPP;
272
273 switch (type) {
274 case TC_SETUP_CLSFLOWER:
275 return ocelot_setup_tc_cls_flower(type_data, cb_priv);
276 case TC_SETUP_CLSMATCHALL:
277 return 0;
278 default:
279 return -EOPNOTSUPP;
280 }
281 }
282
283 static struct ocelot_port_block*
284 ocelot_port_block_create(struct ocelot_port *port)
285 {
286 struct ocelot_port_block *port_block;
287
288 port_block = kzalloc(sizeof(*port_block), GFP_KERNEL);
289 if (!port_block)
290 return NULL;
291
292 port_block->port = port;
293
294 return port_block;
295 }
296
297 static void ocelot_port_block_destroy(struct ocelot_port_block *block)
298 {
299 kfree(block);
300 }
301
302 int ocelot_setup_tc_block_flower_bind(struct ocelot_port *port,
303 struct tc_block_offload *f)
304 {
305 struct ocelot_port_block *port_block;
306 struct tcf_block_cb *block_cb;
307 int ret;
308
309 if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
310 return -EOPNOTSUPP;
311
312 block_cb = tcf_block_cb_lookup(f->block,
313 ocelot_setup_tc_block_cb_flower, port);
314 if (!block_cb) {
315 port_block = ocelot_port_block_create(port);
316 if (!port_block)
317 return -ENOMEM;
318
319 block_cb =
320 __tcf_block_cb_register(f->block,
321 ocelot_setup_tc_block_cb_flower,
322 port, port_block, f->extack);
323 if (IS_ERR(block_cb)) {
324 ret = PTR_ERR(block_cb);
325 goto err_cb_register;
326 }
327 } else {
328 port_block = tcf_block_cb_priv(block_cb);
329 }
330
331 tcf_block_cb_incref(block_cb);
332 return 0;
333
334 err_cb_register:
335 ocelot_port_block_destroy(port_block);
336
337 return ret;
338 }
339
340 void ocelot_setup_tc_block_flower_unbind(struct ocelot_port *port,
341 struct tc_block_offload *f)
342 {
343 struct ocelot_port_block *port_block;
344 struct tcf_block_cb *block_cb;
345
346 block_cb = tcf_block_cb_lookup(f->block,
347 ocelot_setup_tc_block_cb_flower, port);
348 if (!block_cb)
349 return;
350
351 port_block = tcf_block_cb_priv(block_cb);
352 if (!tcf_block_cb_decref(block_cb)) {
353 tcf_block_cb_unregister(f->block,
354 ocelot_setup_tc_block_cb_flower, port);
355 ocelot_port_block_destroy(port_block);
356 }
357 }