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 #include <soc/mscc/ocelot_vcap.h>
9 #include "ocelot_vcap.h"
10
11 /* Arbitrarily chosen constants for encoding the VCAP block and lookup number
12 * into the chain number. This is UAPI.
13 */
14 #define VCAP_BLOCK 10000
15 #define VCAP_LOOKUP 1000
16 #define VCAP_IS1_NUM_LOOKUPS 3
17 #define VCAP_IS2_NUM_LOOKUPS 2
18 #define VCAP_IS2_NUM_PAG 256
19 #define VCAP_IS1_CHAIN(lookup) \
20 (1 * VCAP_BLOCK + (lookup) * VCAP_LOOKUP)
21 #define VCAP_IS2_CHAIN(lookup, pag) \
22 (2 * VCAP_BLOCK + (lookup) * VCAP_LOOKUP + (pag))
23
ocelot_chain_to_block(int chain,bool ingress)24 static int ocelot_chain_to_block(int chain, bool ingress)
25 {
26 int lookup, pag;
27
28 if (!ingress) {
29 if (chain == 0)
30 return VCAP_ES0;
31 return -EOPNOTSUPP;
32 }
33
34 /* Backwards compatibility with older, single-chain tc-flower
35 * offload support in Ocelot
36 */
37 if (chain == 0)
38 return VCAP_IS2;
39
40 for (lookup = 0; lookup < VCAP_IS1_NUM_LOOKUPS; lookup++)
41 if (chain == VCAP_IS1_CHAIN(lookup))
42 return VCAP_IS1;
43
44 for (lookup = 0; lookup < VCAP_IS2_NUM_LOOKUPS; lookup++)
45 for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++)
46 if (chain == VCAP_IS2_CHAIN(lookup, pag))
47 return VCAP_IS2;
48
49 return -EOPNOTSUPP;
50 }
51
52 /* Caller must ensure this is a valid IS1 or IS2 chain first,
53 * by calling ocelot_chain_to_block.
54 */
ocelot_chain_to_lookup(int chain)55 static int ocelot_chain_to_lookup(int chain)
56 {
57 return (chain / VCAP_LOOKUP) % 10;
58 }
59
60 /* Caller must ensure this is a valid IS2 chain first,
61 * by calling ocelot_chain_to_block.
62 */
ocelot_chain_to_pag(int chain)63 static int ocelot_chain_to_pag(int chain)
64 {
65 int lookup = ocelot_chain_to_lookup(chain);
66
67 /* calculate PAG value as chain index relative to the first PAG */
68 return chain - VCAP_IS2_CHAIN(lookup, 0);
69 }
70
ocelot_is_goto_target_valid(int goto_target,int chain,bool ingress)71 static bool ocelot_is_goto_target_valid(int goto_target, int chain,
72 bool ingress)
73 {
74 int pag;
75
76 /* Can't offload GOTO in VCAP ES0 */
77 if (!ingress)
78 return (goto_target < 0);
79
80 /* Non-optional GOTOs */
81 if (chain == 0)
82 /* VCAP IS1 can be skipped, either partially or completely */
83 return (goto_target == VCAP_IS1_CHAIN(0) ||
84 goto_target == VCAP_IS1_CHAIN(1) ||
85 goto_target == VCAP_IS1_CHAIN(2) ||
86 goto_target == VCAP_IS2_CHAIN(0, 0) ||
87 goto_target == VCAP_IS2_CHAIN(1, 0));
88
89 if (chain == VCAP_IS1_CHAIN(0))
90 return (goto_target == VCAP_IS1_CHAIN(1));
91
92 if (chain == VCAP_IS1_CHAIN(1))
93 return (goto_target == VCAP_IS1_CHAIN(2));
94
95 /* Lookup 2 of VCAP IS1 can really support non-optional GOTOs,
96 * using a Policy Association Group (PAG) value, which is an 8-bit
97 * value encoding a VCAP IS2 target chain.
98 */
99 if (chain == VCAP_IS1_CHAIN(2)) {
100 for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++)
101 if (goto_target == VCAP_IS2_CHAIN(0, pag))
102 return true;
103
104 return false;
105 }
106
107 /* Non-optional GOTO from VCAP IS2 lookup 0 to lookup 1.
108 * We cannot change the PAG at this point.
109 */
110 for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++)
111 if (chain == VCAP_IS2_CHAIN(0, pag))
112 return (goto_target == VCAP_IS2_CHAIN(1, pag));
113
114 /* VCAP IS2 lookup 1 cannot jump anywhere */
115 return false;
116 }
117
118 static struct ocelot_vcap_filter *
ocelot_find_vcap_filter_that_points_at(struct ocelot * ocelot,int chain)119 ocelot_find_vcap_filter_that_points_at(struct ocelot *ocelot, int chain)
120 {
121 struct ocelot_vcap_filter *filter;
122 struct ocelot_vcap_block *block;
123 int block_id;
124
125 block_id = ocelot_chain_to_block(chain, true);
126 if (block_id < 0)
127 return NULL;
128
129 if (block_id == VCAP_IS2) {
130 block = &ocelot->block[VCAP_IS1];
131
132 list_for_each_entry(filter, &block->rules, list)
133 if (filter->type == OCELOT_VCAP_FILTER_PAG &&
134 filter->goto_target == chain)
135 return filter;
136 }
137
138 list_for_each_entry(filter, &ocelot->dummy_rules, list)
139 if (filter->goto_target == chain)
140 return filter;
141
142 return NULL;
143 }
144
ocelot_flower_parse_action(struct ocelot * ocelot,int port,bool ingress,struct flow_cls_offload * f,struct ocelot_vcap_filter * filter)145 static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
146 bool ingress, struct flow_cls_offload *f,
147 struct ocelot_vcap_filter *filter)
148 {
149 struct ocelot_port *ocelot_port = ocelot->ports[port];
150 struct netlink_ext_ack *extack = f->common.extack;
151 bool allow_missing_goto_target = false;
152 const struct flow_action_entry *a;
153 enum ocelot_tag_tpid_sel tpid;
154 int i, chain, egress_port;
155 u64 rate;
156
157 if (!flow_action_basic_hw_stats_check(&f->rule->action,
158 f->common.extack))
159 return -EOPNOTSUPP;
160
161 chain = f->common.chain_index;
162 filter->block_id = ocelot_chain_to_block(chain, ingress);
163 if (filter->block_id < 0) {
164 NL_SET_ERR_MSG_MOD(extack, "Cannot offload to this chain");
165 return -EOPNOTSUPP;
166 }
167 if (filter->block_id == VCAP_IS1 || filter->block_id == VCAP_IS2)
168 filter->lookup = ocelot_chain_to_lookup(chain);
169 if (filter->block_id == VCAP_IS2)
170 filter->pag = ocelot_chain_to_pag(chain);
171
172 filter->goto_target = -1;
173 filter->type = OCELOT_VCAP_FILTER_DUMMY;
174
175 flow_action_for_each(i, a, &f->rule->action) {
176 switch (a->id) {
177 case FLOW_ACTION_DROP:
178 if (filter->block_id != VCAP_IS2) {
179 NL_SET_ERR_MSG_MOD(extack,
180 "Drop action can only be offloaded to VCAP IS2");
181 return -EOPNOTSUPP;
182 }
183 if (filter->goto_target != -1) {
184 NL_SET_ERR_MSG_MOD(extack,
185 "Last action must be GOTO");
186 return -EOPNOTSUPP;
187 }
188 filter->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY;
189 filter->action.port_mask = 0;
190 filter->action.police_ena = true;
191 filter->action.pol_ix = OCELOT_POLICER_DISCARD;
192 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
193 break;
194 case FLOW_ACTION_TRAP:
195 if (filter->block_id != VCAP_IS2) {
196 NL_SET_ERR_MSG_MOD(extack,
197 "Trap action can only be offloaded to VCAP IS2");
198 return -EOPNOTSUPP;
199 }
200 if (filter->goto_target != -1) {
201 NL_SET_ERR_MSG_MOD(extack,
202 "Last action must be GOTO");
203 return -EOPNOTSUPP;
204 }
205 filter->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY;
206 filter->action.port_mask = 0;
207 filter->action.cpu_copy_ena = true;
208 filter->action.cpu_qu_num = 0;
209 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
210 break;
211 case FLOW_ACTION_POLICE:
212 if (filter->block_id != VCAP_IS2 ||
213 filter->lookup != 0) {
214 NL_SET_ERR_MSG_MOD(extack,
215 "Police action can only be offloaded to VCAP IS2 lookup 0");
216 return -EOPNOTSUPP;
217 }
218 if (filter->goto_target != -1) {
219 NL_SET_ERR_MSG_MOD(extack,
220 "Last action must be GOTO");
221 return -EOPNOTSUPP;
222 }
223 filter->action.police_ena = true;
224 rate = a->police.rate_bytes_ps;
225 filter->action.pol.rate = div_u64(rate, 1000) * 8;
226 filter->action.pol.burst = a->police.burst;
227 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
228 break;
229 case FLOW_ACTION_REDIRECT:
230 if (filter->block_id != VCAP_IS2) {
231 NL_SET_ERR_MSG_MOD(extack,
232 "Redirect action can only be offloaded to VCAP IS2");
233 return -EOPNOTSUPP;
234 }
235 if (filter->goto_target != -1) {
236 NL_SET_ERR_MSG_MOD(extack,
237 "Last action must be GOTO");
238 return -EOPNOTSUPP;
239 }
240 egress_port = ocelot->ops->netdev_to_port(a->dev);
241 if (egress_port < 0) {
242 NL_SET_ERR_MSG_MOD(extack,
243 "Destination not an ocelot port");
244 return -EOPNOTSUPP;
245 }
246 filter->action.mask_mode = OCELOT_MASK_MODE_REDIRECT;
247 filter->action.port_mask = BIT(egress_port);
248 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
249 break;
250 case FLOW_ACTION_VLAN_POP:
251 if (filter->block_id != VCAP_IS1) {
252 NL_SET_ERR_MSG_MOD(extack,
253 "VLAN pop action can only be offloaded to VCAP IS1");
254 return -EOPNOTSUPP;
255 }
256 if (filter->goto_target != -1) {
257 NL_SET_ERR_MSG_MOD(extack,
258 "Last action must be GOTO");
259 return -EOPNOTSUPP;
260 }
261 filter->action.vlan_pop_cnt_ena = true;
262 filter->action.vlan_pop_cnt++;
263 if (filter->action.vlan_pop_cnt > 2) {
264 NL_SET_ERR_MSG_MOD(extack,
265 "Cannot pop more than 2 VLAN headers");
266 return -EOPNOTSUPP;
267 }
268 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
269 break;
270 case FLOW_ACTION_VLAN_MANGLE:
271 if (filter->block_id != VCAP_IS1) {
272 NL_SET_ERR_MSG_MOD(extack,
273 "VLAN modify action can only be offloaded to VCAP IS1");
274 return -EOPNOTSUPP;
275 }
276 if (filter->goto_target != -1) {
277 NL_SET_ERR_MSG_MOD(extack,
278 "Last action must be GOTO");
279 return -EOPNOTSUPP;
280 }
281 if (!ocelot_port->vlan_aware) {
282 NL_SET_ERR_MSG_MOD(extack,
283 "Can only modify VLAN under VLAN aware bridge");
284 return -EOPNOTSUPP;
285 }
286 filter->action.vid_replace_ena = true;
287 filter->action.pcp_dei_ena = true;
288 filter->action.vid = a->vlan.vid;
289 filter->action.pcp = a->vlan.prio;
290 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
291 break;
292 case FLOW_ACTION_PRIORITY:
293 if (filter->block_id != VCAP_IS1) {
294 NL_SET_ERR_MSG_MOD(extack,
295 "Priority action can only be offloaded to VCAP IS1");
296 return -EOPNOTSUPP;
297 }
298 if (filter->goto_target != -1) {
299 NL_SET_ERR_MSG_MOD(extack,
300 "Last action must be GOTO");
301 return -EOPNOTSUPP;
302 }
303 filter->action.qos_ena = true;
304 filter->action.qos_val = a->priority;
305 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
306 break;
307 case FLOW_ACTION_GOTO:
308 filter->goto_target = a->chain_index;
309
310 if (filter->block_id == VCAP_IS1 && filter->lookup == 2) {
311 int pag = ocelot_chain_to_pag(filter->goto_target);
312
313 filter->action.pag_override_mask = 0xff;
314 filter->action.pag_val = pag;
315 filter->type = OCELOT_VCAP_FILTER_PAG;
316 }
317 break;
318 case FLOW_ACTION_VLAN_PUSH:
319 if (filter->block_id != VCAP_ES0) {
320 NL_SET_ERR_MSG_MOD(extack,
321 "VLAN push action can only be offloaded to VCAP ES0");
322 return -EOPNOTSUPP;
323 }
324 switch (ntohs(a->vlan.proto)) {
325 case ETH_P_8021Q:
326 tpid = OCELOT_TAG_TPID_SEL_8021Q;
327 break;
328 case ETH_P_8021AD:
329 tpid = OCELOT_TAG_TPID_SEL_8021AD;
330 break;
331 default:
332 NL_SET_ERR_MSG_MOD(extack,
333 "Cannot push custom TPID");
334 return -EOPNOTSUPP;
335 }
336 filter->action.tag_a_tpid_sel = tpid;
337 filter->action.push_outer_tag = OCELOT_ES0_TAG;
338 filter->action.tag_a_vid_sel = 1;
339 filter->action.vid_a_val = a->vlan.vid;
340 filter->action.pcp_a_val = a->vlan.prio;
341 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
342 break;
343 default:
344 NL_SET_ERR_MSG_MOD(extack, "Cannot offload action");
345 return -EOPNOTSUPP;
346 }
347 }
348
349 if (filter->goto_target == -1) {
350 if ((filter->block_id == VCAP_IS2 && filter->lookup == 1) ||
351 chain == 0) {
352 allow_missing_goto_target = true;
353 } else {
354 NL_SET_ERR_MSG_MOD(extack, "Missing GOTO action");
355 return -EOPNOTSUPP;
356 }
357 }
358
359 if (!ocelot_is_goto_target_valid(filter->goto_target, chain, ingress) &&
360 !allow_missing_goto_target) {
361 NL_SET_ERR_MSG_MOD(extack, "Cannot offload this GOTO target");
362 return -EOPNOTSUPP;
363 }
364
365 return 0;
366 }
367
ocelot_flower_parse_indev(struct ocelot * ocelot,int port,struct flow_cls_offload * f,struct ocelot_vcap_filter * filter)368 static int ocelot_flower_parse_indev(struct ocelot *ocelot, int port,
369 struct flow_cls_offload *f,
370 struct ocelot_vcap_filter *filter)
371 {
372 struct flow_rule *rule = flow_cls_offload_flow_rule(f);
373 const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0];
374 int key_length = vcap->keys[VCAP_ES0_IGR_PORT].length;
375 struct netlink_ext_ack *extack = f->common.extack;
376 struct net_device *dev, *indev;
377 struct flow_match_meta match;
378 int ingress_port;
379
380 flow_rule_match_meta(rule, &match);
381
382 if (!match.mask->ingress_ifindex)
383 return 0;
384
385 if (match.mask->ingress_ifindex != 0xFFFFFFFF) {
386 NL_SET_ERR_MSG_MOD(extack, "Unsupported ingress ifindex mask");
387 return -EOPNOTSUPP;
388 }
389
390 dev = ocelot->ops->port_to_netdev(ocelot, port);
391 if (!dev)
392 return -EINVAL;
393
394 indev = __dev_get_by_index(dev_net(dev), match.key->ingress_ifindex);
395 if (!indev) {
396 NL_SET_ERR_MSG_MOD(extack,
397 "Can't find the ingress port to match on");
398 return -ENOENT;
399 }
400
401 ingress_port = ocelot->ops->netdev_to_port(indev);
402 if (ingress_port < 0) {
403 NL_SET_ERR_MSG_MOD(extack,
404 "Can only offload an ocelot ingress port");
405 return -EOPNOTSUPP;
406 }
407 if (ingress_port == port) {
408 NL_SET_ERR_MSG_MOD(extack,
409 "Ingress port is equal to the egress port");
410 return -EINVAL;
411 }
412
413 filter->ingress_port.value = ingress_port;
414 filter->ingress_port.mask = GENMASK(key_length - 1, 0);
415
416 return 0;
417 }
418
419 static int
ocelot_flower_parse_key(struct ocelot * ocelot,int port,bool ingress,struct flow_cls_offload * f,struct ocelot_vcap_filter * filter)420 ocelot_flower_parse_key(struct ocelot *ocelot, int port, bool ingress,
421 struct flow_cls_offload *f,
422 struct ocelot_vcap_filter *filter)
423 {
424 struct flow_rule *rule = flow_cls_offload_flow_rule(f);
425 struct flow_dissector *dissector = rule->match.dissector;
426 struct netlink_ext_ack *extack = f->common.extack;
427 u16 proto = ntohs(f->common.protocol);
428 bool match_protocol = true;
429 int ret;
430
431 if (dissector->used_keys &
432 ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
433 BIT(FLOW_DISSECTOR_KEY_BASIC) |
434 BIT(FLOW_DISSECTOR_KEY_META) |
435 BIT(FLOW_DISSECTOR_KEY_PORTS) |
436 BIT(FLOW_DISSECTOR_KEY_VLAN) |
437 BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
438 BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
439 BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
440 return -EOPNOTSUPP;
441 }
442
443 /* For VCAP ES0 (egress rewriter) we can match on the ingress port */
444 if (!ingress) {
445 ret = ocelot_flower_parse_indev(ocelot, port, f, filter);
446 if (ret)
447 return ret;
448 }
449
450 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
451 struct flow_match_control match;
452
453 flow_rule_match_control(rule, &match);
454 }
455
456 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
457 struct flow_match_eth_addrs match;
458
459 if (filter->block_id == VCAP_ES0) {
460 NL_SET_ERR_MSG_MOD(extack,
461 "VCAP ES0 cannot match on MAC address");
462 return -EOPNOTSUPP;
463 }
464
465 /* The hw support mac matches only for MAC_ETYPE key,
466 * therefore if other matches(port, tcp flags, etc) are added
467 * then just bail out
468 */
469 if ((dissector->used_keys &
470 (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
471 BIT(FLOW_DISSECTOR_KEY_BASIC) |
472 BIT(FLOW_DISSECTOR_KEY_CONTROL))) !=
473 (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
474 BIT(FLOW_DISSECTOR_KEY_BASIC) |
475 BIT(FLOW_DISSECTOR_KEY_CONTROL)))
476 return -EOPNOTSUPP;
477
478 flow_rule_match_eth_addrs(rule, &match);
479
480 if (filter->block_id == VCAP_IS1 &&
481 !is_zero_ether_addr(match.mask->dst)) {
482 NL_SET_ERR_MSG_MOD(extack,
483 "Key type S1_NORMAL cannot match on destination MAC");
484 return -EOPNOTSUPP;
485 }
486
487 filter->key_type = OCELOT_VCAP_KEY_ETYPE;
488 ether_addr_copy(filter->key.etype.dmac.value,
489 match.key->dst);
490 ether_addr_copy(filter->key.etype.smac.value,
491 match.key->src);
492 ether_addr_copy(filter->key.etype.dmac.mask,
493 match.mask->dst);
494 ether_addr_copy(filter->key.etype.smac.mask,
495 match.mask->src);
496 goto finished_key_parsing;
497 }
498
499 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
500 struct flow_match_basic match;
501
502 flow_rule_match_basic(rule, &match);
503 if (ntohs(match.key->n_proto) == ETH_P_IP) {
504 if (filter->block_id == VCAP_ES0) {
505 NL_SET_ERR_MSG_MOD(extack,
506 "VCAP ES0 cannot match on IP protocol");
507 return -EOPNOTSUPP;
508 }
509
510 filter->key_type = OCELOT_VCAP_KEY_IPV4;
511 filter->key.ipv4.proto.value[0] =
512 match.key->ip_proto;
513 filter->key.ipv4.proto.mask[0] =
514 match.mask->ip_proto;
515 match_protocol = false;
516 }
517 if (ntohs(match.key->n_proto) == ETH_P_IPV6) {
518 if (filter->block_id == VCAP_ES0) {
519 NL_SET_ERR_MSG_MOD(extack,
520 "VCAP ES0 cannot match on IP protocol");
521 return -EOPNOTSUPP;
522 }
523
524 filter->key_type = OCELOT_VCAP_KEY_IPV6;
525 filter->key.ipv6.proto.value[0] =
526 match.key->ip_proto;
527 filter->key.ipv6.proto.mask[0] =
528 match.mask->ip_proto;
529 match_protocol = false;
530 }
531 }
532
533 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS) &&
534 proto == ETH_P_IP) {
535 struct flow_match_ipv4_addrs match;
536 u8 *tmp;
537
538 if (filter->block_id == VCAP_ES0) {
539 NL_SET_ERR_MSG_MOD(extack,
540 "VCAP ES0 cannot match on IP address");
541 return -EOPNOTSUPP;
542 }
543
544 flow_rule_match_ipv4_addrs(rule, &match);
545
546 if (filter->block_id == VCAP_IS1 && *(u32 *)&match.mask->dst) {
547 NL_SET_ERR_MSG_MOD(extack,
548 "Key type S1_NORMAL cannot match on destination IP");
549 return -EOPNOTSUPP;
550 }
551
552 tmp = &filter->key.ipv4.sip.value.addr[0];
553 memcpy(tmp, &match.key->src, 4);
554
555 tmp = &filter->key.ipv4.sip.mask.addr[0];
556 memcpy(tmp, &match.mask->src, 4);
557
558 tmp = &filter->key.ipv4.dip.value.addr[0];
559 memcpy(tmp, &match.key->dst, 4);
560
561 tmp = &filter->key.ipv4.dip.mask.addr[0];
562 memcpy(tmp, &match.mask->dst, 4);
563 match_protocol = false;
564 }
565
566 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS) &&
567 proto == ETH_P_IPV6) {
568 return -EOPNOTSUPP;
569 }
570
571 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
572 struct flow_match_ports match;
573
574 if (filter->block_id == VCAP_ES0) {
575 NL_SET_ERR_MSG_MOD(extack,
576 "VCAP ES0 cannot match on L4 ports");
577 return -EOPNOTSUPP;
578 }
579
580 flow_rule_match_ports(rule, &match);
581 filter->key.ipv4.sport.value = ntohs(match.key->src);
582 filter->key.ipv4.sport.mask = ntohs(match.mask->src);
583 filter->key.ipv4.dport.value = ntohs(match.key->dst);
584 filter->key.ipv4.dport.mask = ntohs(match.mask->dst);
585 match_protocol = false;
586 }
587
588 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
589 struct flow_match_vlan match;
590
591 flow_rule_match_vlan(rule, &match);
592 filter->key_type = OCELOT_VCAP_KEY_ANY;
593 filter->vlan.vid.value = match.key->vlan_id;
594 filter->vlan.vid.mask = match.mask->vlan_id;
595 filter->vlan.pcp.value[0] = match.key->vlan_priority;
596 filter->vlan.pcp.mask[0] = match.mask->vlan_priority;
597 match_protocol = false;
598 }
599
600 finished_key_parsing:
601 if (match_protocol && proto != ETH_P_ALL) {
602 if (filter->block_id == VCAP_ES0) {
603 NL_SET_ERR_MSG_MOD(extack,
604 "VCAP ES0 cannot match on L2 proto");
605 return -EOPNOTSUPP;
606 }
607
608 /* TODO: support SNAP, LLC etc */
609 if (proto < ETH_P_802_3_MIN)
610 return -EOPNOTSUPP;
611 filter->key_type = OCELOT_VCAP_KEY_ETYPE;
612 *(__be16 *)filter->key.etype.etype.value = htons(proto);
613 *(__be16 *)filter->key.etype.etype.mask = htons(0xffff);
614 }
615 /* else, a filter of type OCELOT_VCAP_KEY_ANY is implicitly added */
616
617 return 0;
618 }
619
ocelot_flower_parse(struct ocelot * ocelot,int port,bool ingress,struct flow_cls_offload * f,struct ocelot_vcap_filter * filter)620 static int ocelot_flower_parse(struct ocelot *ocelot, int port, bool ingress,
621 struct flow_cls_offload *f,
622 struct ocelot_vcap_filter *filter)
623 {
624 int ret;
625
626 filter->prio = f->common.prio;
627 filter->id = f->cookie;
628
629 ret = ocelot_flower_parse_action(ocelot, port, ingress, f, filter);
630 if (ret)
631 return ret;
632
633 return ocelot_flower_parse_key(ocelot, port, ingress, f, filter);
634 }
635
636 static struct ocelot_vcap_filter
ocelot_vcap_filter_create(struct ocelot * ocelot,int port,bool ingress,struct flow_cls_offload * f)637 *ocelot_vcap_filter_create(struct ocelot *ocelot, int port, bool ingress,
638 struct flow_cls_offload *f)
639 {
640 struct ocelot_vcap_filter *filter;
641
642 filter = kzalloc(sizeof(*filter), GFP_KERNEL);
643 if (!filter)
644 return NULL;
645
646 if (ingress) {
647 filter->ingress_port_mask = BIT(port);
648 } else {
649 const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0];
650 int key_length = vcap->keys[VCAP_ES0_EGR_PORT].length;
651
652 filter->egress_port.value = port;
653 filter->egress_port.mask = GENMASK(key_length - 1, 0);
654 }
655
656 return filter;
657 }
658
ocelot_vcap_dummy_filter_add(struct ocelot * ocelot,struct ocelot_vcap_filter * filter)659 static int ocelot_vcap_dummy_filter_add(struct ocelot *ocelot,
660 struct ocelot_vcap_filter *filter)
661 {
662 list_add(&filter->list, &ocelot->dummy_rules);
663
664 return 0;
665 }
666
ocelot_vcap_dummy_filter_del(struct ocelot * ocelot,struct ocelot_vcap_filter * filter)667 static int ocelot_vcap_dummy_filter_del(struct ocelot *ocelot,
668 struct ocelot_vcap_filter *filter)
669 {
670 list_del(&filter->list);
671 kfree(filter);
672
673 return 0;
674 }
675
ocelot_cls_flower_replace(struct ocelot * ocelot,int port,struct flow_cls_offload * f,bool ingress)676 int ocelot_cls_flower_replace(struct ocelot *ocelot, int port,
677 struct flow_cls_offload *f, bool ingress)
678 {
679 struct netlink_ext_ack *extack = f->common.extack;
680 struct ocelot_vcap_filter *filter;
681 int chain = f->common.chain_index;
682 int ret;
683
684 if (chain && !ocelot_find_vcap_filter_that_points_at(ocelot, chain)) {
685 NL_SET_ERR_MSG_MOD(extack, "No default GOTO action points to this chain");
686 return -EOPNOTSUPP;
687 }
688
689 filter = ocelot_vcap_filter_create(ocelot, port, ingress, f);
690 if (!filter)
691 return -ENOMEM;
692
693 ret = ocelot_flower_parse(ocelot, port, ingress, f, filter);
694 if (ret) {
695 kfree(filter);
696 return ret;
697 }
698
699 /* The non-optional GOTOs for the TCAM skeleton don't need
700 * to be actually offloaded.
701 */
702 if (filter->type == OCELOT_VCAP_FILTER_DUMMY)
703 return ocelot_vcap_dummy_filter_add(ocelot, filter);
704
705 return ocelot_vcap_filter_add(ocelot, filter, f->common.extack);
706 }
707 EXPORT_SYMBOL_GPL(ocelot_cls_flower_replace);
708
ocelot_cls_flower_destroy(struct ocelot * ocelot,int port,struct flow_cls_offload * f,bool ingress)709 int ocelot_cls_flower_destroy(struct ocelot *ocelot, int port,
710 struct flow_cls_offload *f, bool ingress)
711 {
712 struct ocelot_vcap_filter *filter;
713 struct ocelot_vcap_block *block;
714 int block_id;
715
716 block_id = ocelot_chain_to_block(f->common.chain_index, ingress);
717 if (block_id < 0)
718 return 0;
719
720 block = &ocelot->block[block_id];
721
722 filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie);
723 if (!filter)
724 return 0;
725
726 if (filter->type == OCELOT_VCAP_FILTER_DUMMY)
727 return ocelot_vcap_dummy_filter_del(ocelot, filter);
728
729 return ocelot_vcap_filter_del(ocelot, filter);
730 }
731 EXPORT_SYMBOL_GPL(ocelot_cls_flower_destroy);
732
ocelot_cls_flower_stats(struct ocelot * ocelot,int port,struct flow_cls_offload * f,bool ingress)733 int ocelot_cls_flower_stats(struct ocelot *ocelot, int port,
734 struct flow_cls_offload *f, bool ingress)
735 {
736 struct ocelot_vcap_filter *filter;
737 struct ocelot_vcap_block *block;
738 int block_id, ret;
739
740 block_id = ocelot_chain_to_block(f->common.chain_index, ingress);
741 if (block_id < 0)
742 return 0;
743
744 block = &ocelot->block[block_id];
745
746 filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie);
747 if (!filter || filter->type == OCELOT_VCAP_FILTER_DUMMY)
748 return 0;
749
750 ret = ocelot_vcap_filter_stats_update(ocelot, filter);
751 if (ret)
752 return ret;
753
754 flow_stats_update(&f->stats, 0x0, filter->stats.pkts, 0, 0x0,
755 FLOW_ACTION_HW_STATS_IMMEDIATE);
756 return 0;
757 }
758 EXPORT_SYMBOL_GPL(ocelot_cls_flower_stats);
759