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
145 static int
ocelot_flower_parse_ingress_vlan_modify(struct ocelot * ocelot,int port,struct ocelot_vcap_filter * filter,const struct flow_action_entry * a,struct netlink_ext_ack * extack)146 ocelot_flower_parse_ingress_vlan_modify(struct ocelot *ocelot, int port,
147 struct ocelot_vcap_filter *filter,
148 const struct flow_action_entry *a,
149 struct netlink_ext_ack *extack)
150 {
151 struct ocelot_port *ocelot_port = ocelot->ports[port];
152
153 if (filter->goto_target != -1) {
154 NL_SET_ERR_MSG_MOD(extack,
155 "Last action must be GOTO");
156 return -EOPNOTSUPP;
157 }
158
159 if (!ocelot_port->vlan_aware) {
160 NL_SET_ERR_MSG_MOD(extack,
161 "Can only modify VLAN under VLAN aware bridge");
162 return -EOPNOTSUPP;
163 }
164
165 filter->action.vid_replace_ena = true;
166 filter->action.pcp_dei_ena = true;
167 filter->action.vid = a->vlan.vid;
168 filter->action.pcp = a->vlan.prio;
169 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
170
171 return 0;
172 }
173
174 static int
ocelot_flower_parse_egress_vlan_modify(struct ocelot_vcap_filter * filter,const struct flow_action_entry * a,struct netlink_ext_ack * extack)175 ocelot_flower_parse_egress_vlan_modify(struct ocelot_vcap_filter *filter,
176 const struct flow_action_entry *a,
177 struct netlink_ext_ack *extack)
178 {
179 enum ocelot_tag_tpid_sel tpid;
180
181 switch (ntohs(a->vlan.proto)) {
182 case ETH_P_8021Q:
183 tpid = OCELOT_TAG_TPID_SEL_8021Q;
184 break;
185 case ETH_P_8021AD:
186 tpid = OCELOT_TAG_TPID_SEL_8021AD;
187 break;
188 default:
189 NL_SET_ERR_MSG_MOD(extack,
190 "Cannot modify custom TPID");
191 return -EOPNOTSUPP;
192 }
193
194 filter->action.tag_a_tpid_sel = tpid;
195 filter->action.push_outer_tag = OCELOT_ES0_TAG;
196 filter->action.tag_a_vid_sel = OCELOT_ES0_VID_PLUS_CLASSIFIED_VID;
197 filter->action.vid_a_val = a->vlan.vid;
198 filter->action.pcp_a_val = a->vlan.prio;
199 filter->action.tag_a_pcp_sel = OCELOT_ES0_PCP;
200 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
201
202 return 0;
203 }
204
ocelot_flower_parse_action(struct ocelot * ocelot,int port,bool ingress,struct flow_cls_offload * f,struct ocelot_vcap_filter * filter)205 static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
206 bool ingress, struct flow_cls_offload *f,
207 struct ocelot_vcap_filter *filter)
208 {
209 struct netlink_ext_ack *extack = f->common.extack;
210 bool allow_missing_goto_target = false;
211 const struct flow_action_entry *a;
212 enum ocelot_tag_tpid_sel tpid;
213 int i, chain, egress_port;
214 u64 rate;
215 int err;
216
217 if (!flow_action_basic_hw_stats_check(&f->rule->action,
218 f->common.extack))
219 return -EOPNOTSUPP;
220
221 chain = f->common.chain_index;
222 filter->block_id = ocelot_chain_to_block(chain, ingress);
223 if (filter->block_id < 0) {
224 NL_SET_ERR_MSG_MOD(extack, "Cannot offload to this chain");
225 return -EOPNOTSUPP;
226 }
227 if (filter->block_id == VCAP_IS1 || filter->block_id == VCAP_IS2)
228 filter->lookup = ocelot_chain_to_lookup(chain);
229 if (filter->block_id == VCAP_IS2)
230 filter->pag = ocelot_chain_to_pag(chain);
231
232 filter->goto_target = -1;
233 filter->type = OCELOT_VCAP_FILTER_DUMMY;
234
235 flow_action_for_each(i, a, &f->rule->action) {
236 switch (a->id) {
237 case FLOW_ACTION_DROP:
238 if (filter->block_id != VCAP_IS2) {
239 NL_SET_ERR_MSG_MOD(extack,
240 "Drop action can only be offloaded to VCAP IS2");
241 return -EOPNOTSUPP;
242 }
243 if (filter->goto_target != -1) {
244 NL_SET_ERR_MSG_MOD(extack,
245 "Last action must be GOTO");
246 return -EOPNOTSUPP;
247 }
248 filter->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY;
249 filter->action.port_mask = 0;
250 filter->action.police_ena = true;
251 filter->action.pol_ix = OCELOT_POLICER_DISCARD;
252 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
253 break;
254 case FLOW_ACTION_TRAP:
255 if (filter->block_id != VCAP_IS2) {
256 NL_SET_ERR_MSG_MOD(extack,
257 "Trap action can only be offloaded to VCAP IS2");
258 return -EOPNOTSUPP;
259 }
260 if (filter->goto_target != -1) {
261 NL_SET_ERR_MSG_MOD(extack,
262 "Last action must be GOTO");
263 return -EOPNOTSUPP;
264 }
265 filter->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY;
266 filter->action.port_mask = 0;
267 filter->action.cpu_copy_ena = true;
268 filter->action.cpu_qu_num = 0;
269 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
270 break;
271 case FLOW_ACTION_POLICE:
272 if (filter->block_id != VCAP_IS2 ||
273 filter->lookup != 0) {
274 NL_SET_ERR_MSG_MOD(extack,
275 "Police action can only be offloaded to VCAP IS2 lookup 0");
276 return -EOPNOTSUPP;
277 }
278 if (filter->goto_target != -1) {
279 NL_SET_ERR_MSG_MOD(extack,
280 "Last action must be GOTO");
281 return -EOPNOTSUPP;
282 }
283 if (a->police.rate_pkt_ps) {
284 NL_SET_ERR_MSG_MOD(extack,
285 "QoS offload not support packets per second");
286 return -EOPNOTSUPP;
287 }
288 filter->action.police_ena = true;
289 rate = a->police.rate_bytes_ps;
290 filter->action.pol.rate = div_u64(rate, 1000) * 8;
291 filter->action.pol.burst = a->police.burst;
292 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
293 break;
294 case FLOW_ACTION_REDIRECT:
295 if (filter->block_id != VCAP_IS2) {
296 NL_SET_ERR_MSG_MOD(extack,
297 "Redirect action can only be offloaded to VCAP IS2");
298 return -EOPNOTSUPP;
299 }
300 if (filter->goto_target != -1) {
301 NL_SET_ERR_MSG_MOD(extack,
302 "Last action must be GOTO");
303 return -EOPNOTSUPP;
304 }
305 egress_port = ocelot->ops->netdev_to_port(a->dev);
306 if (egress_port < 0) {
307 NL_SET_ERR_MSG_MOD(extack,
308 "Destination not an ocelot port");
309 return -EOPNOTSUPP;
310 }
311 filter->action.mask_mode = OCELOT_MASK_MODE_REDIRECT;
312 filter->action.port_mask = BIT(egress_port);
313 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
314 break;
315 case FLOW_ACTION_VLAN_POP:
316 if (filter->block_id != VCAP_IS1) {
317 NL_SET_ERR_MSG_MOD(extack,
318 "VLAN pop action can only be offloaded to VCAP IS1");
319 return -EOPNOTSUPP;
320 }
321 if (filter->goto_target != -1) {
322 NL_SET_ERR_MSG_MOD(extack,
323 "Last action must be GOTO");
324 return -EOPNOTSUPP;
325 }
326 filter->action.vlan_pop_cnt_ena = true;
327 filter->action.vlan_pop_cnt++;
328 if (filter->action.vlan_pop_cnt > 2) {
329 NL_SET_ERR_MSG_MOD(extack,
330 "Cannot pop more than 2 VLAN headers");
331 return -EOPNOTSUPP;
332 }
333 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
334 break;
335 case FLOW_ACTION_VLAN_MANGLE:
336 if (filter->block_id == VCAP_IS1) {
337 err = ocelot_flower_parse_ingress_vlan_modify(ocelot, port,
338 filter, a,
339 extack);
340 } else if (filter->block_id == VCAP_ES0) {
341 err = ocelot_flower_parse_egress_vlan_modify(filter, a,
342 extack);
343 } else {
344 NL_SET_ERR_MSG_MOD(extack,
345 "VLAN modify action can only be offloaded to VCAP IS1 or ES0");
346 err = -EOPNOTSUPP;
347 }
348 if (err)
349 return err;
350 break;
351 case FLOW_ACTION_PRIORITY:
352 if (filter->block_id != VCAP_IS1) {
353 NL_SET_ERR_MSG_MOD(extack,
354 "Priority action can only be offloaded to VCAP IS1");
355 return -EOPNOTSUPP;
356 }
357 if (filter->goto_target != -1) {
358 NL_SET_ERR_MSG_MOD(extack,
359 "Last action must be GOTO");
360 return -EOPNOTSUPP;
361 }
362 filter->action.qos_ena = true;
363 filter->action.qos_val = a->priority;
364 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
365 break;
366 case FLOW_ACTION_GOTO:
367 filter->goto_target = a->chain_index;
368
369 if (filter->block_id == VCAP_IS1 && filter->lookup == 2) {
370 int pag = ocelot_chain_to_pag(filter->goto_target);
371
372 filter->action.pag_override_mask = 0xff;
373 filter->action.pag_val = pag;
374 filter->type = OCELOT_VCAP_FILTER_PAG;
375 }
376 break;
377 case FLOW_ACTION_VLAN_PUSH:
378 if (filter->block_id != VCAP_ES0) {
379 NL_SET_ERR_MSG_MOD(extack,
380 "VLAN push action can only be offloaded to VCAP ES0");
381 return -EOPNOTSUPP;
382 }
383 switch (ntohs(a->vlan.proto)) {
384 case ETH_P_8021Q:
385 tpid = OCELOT_TAG_TPID_SEL_8021Q;
386 break;
387 case ETH_P_8021AD:
388 tpid = OCELOT_TAG_TPID_SEL_8021AD;
389 break;
390 default:
391 NL_SET_ERR_MSG_MOD(extack,
392 "Cannot push custom TPID");
393 return -EOPNOTSUPP;
394 }
395 filter->action.tag_a_tpid_sel = tpid;
396 filter->action.push_outer_tag = OCELOT_ES0_TAG;
397 filter->action.tag_a_vid_sel = OCELOT_ES0_VID;
398 filter->action.vid_a_val = a->vlan.vid;
399 filter->action.pcp_a_val = a->vlan.prio;
400 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
401 break;
402 default:
403 NL_SET_ERR_MSG_MOD(extack, "Cannot offload action");
404 return -EOPNOTSUPP;
405 }
406 }
407
408 if (filter->goto_target == -1) {
409 if ((filter->block_id == VCAP_IS2 && filter->lookup == 1) ||
410 chain == 0) {
411 allow_missing_goto_target = true;
412 } else {
413 NL_SET_ERR_MSG_MOD(extack, "Missing GOTO action");
414 return -EOPNOTSUPP;
415 }
416 }
417
418 if (!ocelot_is_goto_target_valid(filter->goto_target, chain, ingress) &&
419 !allow_missing_goto_target) {
420 NL_SET_ERR_MSG_MOD(extack, "Cannot offload this GOTO target");
421 return -EOPNOTSUPP;
422 }
423
424 return 0;
425 }
426
ocelot_flower_parse_indev(struct ocelot * ocelot,int port,struct flow_cls_offload * f,struct ocelot_vcap_filter * filter)427 static int ocelot_flower_parse_indev(struct ocelot *ocelot, int port,
428 struct flow_cls_offload *f,
429 struct ocelot_vcap_filter *filter)
430 {
431 struct flow_rule *rule = flow_cls_offload_flow_rule(f);
432 const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0];
433 int key_length = vcap->keys[VCAP_ES0_IGR_PORT].length;
434 struct netlink_ext_ack *extack = f->common.extack;
435 struct net_device *dev, *indev;
436 struct flow_match_meta match;
437 int ingress_port;
438
439 flow_rule_match_meta(rule, &match);
440
441 if (!match.mask->ingress_ifindex)
442 return 0;
443
444 if (match.mask->ingress_ifindex != 0xFFFFFFFF) {
445 NL_SET_ERR_MSG_MOD(extack, "Unsupported ingress ifindex mask");
446 return -EOPNOTSUPP;
447 }
448
449 dev = ocelot->ops->port_to_netdev(ocelot, port);
450 if (!dev)
451 return -EINVAL;
452
453 indev = __dev_get_by_index(dev_net(dev), match.key->ingress_ifindex);
454 if (!indev) {
455 NL_SET_ERR_MSG_MOD(extack,
456 "Can't find the ingress port to match on");
457 return -ENOENT;
458 }
459
460 ingress_port = ocelot->ops->netdev_to_port(indev);
461 if (ingress_port < 0) {
462 NL_SET_ERR_MSG_MOD(extack,
463 "Can only offload an ocelot ingress port");
464 return -EOPNOTSUPP;
465 }
466 if (ingress_port == port) {
467 NL_SET_ERR_MSG_MOD(extack,
468 "Ingress port is equal to the egress port");
469 return -EINVAL;
470 }
471
472 filter->ingress_port.value = ingress_port;
473 filter->ingress_port.mask = GENMASK(key_length - 1, 0);
474
475 return 0;
476 }
477
478 static int
ocelot_flower_parse_key(struct ocelot * ocelot,int port,bool ingress,struct flow_cls_offload * f,struct ocelot_vcap_filter * filter)479 ocelot_flower_parse_key(struct ocelot *ocelot, int port, bool ingress,
480 struct flow_cls_offload *f,
481 struct ocelot_vcap_filter *filter)
482 {
483 struct flow_rule *rule = flow_cls_offload_flow_rule(f);
484 struct flow_dissector *dissector = rule->match.dissector;
485 struct netlink_ext_ack *extack = f->common.extack;
486 u16 proto = ntohs(f->common.protocol);
487 bool match_protocol = true;
488 int ret;
489
490 if (dissector->used_keys &
491 ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
492 BIT(FLOW_DISSECTOR_KEY_BASIC) |
493 BIT(FLOW_DISSECTOR_KEY_META) |
494 BIT(FLOW_DISSECTOR_KEY_PORTS) |
495 BIT(FLOW_DISSECTOR_KEY_VLAN) |
496 BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
497 BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
498 BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
499 return -EOPNOTSUPP;
500 }
501
502 /* For VCAP ES0 (egress rewriter) we can match on the ingress port */
503 if (!ingress) {
504 ret = ocelot_flower_parse_indev(ocelot, port, f, filter);
505 if (ret)
506 return ret;
507 }
508
509 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
510 struct flow_match_control match;
511
512 flow_rule_match_control(rule, &match);
513 }
514
515 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
516 struct flow_match_eth_addrs match;
517
518 if (filter->block_id == VCAP_ES0) {
519 NL_SET_ERR_MSG_MOD(extack,
520 "VCAP ES0 cannot match on MAC address");
521 return -EOPNOTSUPP;
522 }
523
524 if (filter->block_id == VCAP_IS1 &&
525 !is_zero_ether_addr(match.mask->dst)) {
526 NL_SET_ERR_MSG_MOD(extack,
527 "Key type S1_NORMAL cannot match on destination MAC");
528 return -EOPNOTSUPP;
529 }
530
531 /* The hw support mac matches only for MAC_ETYPE key,
532 * therefore if other matches(port, tcp flags, etc) are added
533 * then just bail out
534 */
535 if ((dissector->used_keys &
536 (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
537 BIT(FLOW_DISSECTOR_KEY_BASIC) |
538 BIT(FLOW_DISSECTOR_KEY_CONTROL))) !=
539 (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
540 BIT(FLOW_DISSECTOR_KEY_BASIC) |
541 BIT(FLOW_DISSECTOR_KEY_CONTROL)))
542 return -EOPNOTSUPP;
543
544 flow_rule_match_eth_addrs(rule, &match);
545 filter->key_type = OCELOT_VCAP_KEY_ETYPE;
546 ether_addr_copy(filter->key.etype.dmac.value,
547 match.key->dst);
548 ether_addr_copy(filter->key.etype.smac.value,
549 match.key->src);
550 ether_addr_copy(filter->key.etype.dmac.mask,
551 match.mask->dst);
552 ether_addr_copy(filter->key.etype.smac.mask,
553 match.mask->src);
554 goto finished_key_parsing;
555 }
556
557 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
558 struct flow_match_basic match;
559
560 flow_rule_match_basic(rule, &match);
561 if (ntohs(match.key->n_proto) == ETH_P_IP) {
562 if (filter->block_id == VCAP_ES0) {
563 NL_SET_ERR_MSG_MOD(extack,
564 "VCAP ES0 cannot match on IP protocol");
565 return -EOPNOTSUPP;
566 }
567
568 filter->key_type = OCELOT_VCAP_KEY_IPV4;
569 filter->key.ipv4.proto.value[0] =
570 match.key->ip_proto;
571 filter->key.ipv4.proto.mask[0] =
572 match.mask->ip_proto;
573 match_protocol = false;
574 }
575 if (ntohs(match.key->n_proto) == ETH_P_IPV6) {
576 if (filter->block_id == VCAP_ES0) {
577 NL_SET_ERR_MSG_MOD(extack,
578 "VCAP ES0 cannot match on IP protocol");
579 return -EOPNOTSUPP;
580 }
581
582 filter->key_type = OCELOT_VCAP_KEY_IPV6;
583 filter->key.ipv6.proto.value[0] =
584 match.key->ip_proto;
585 filter->key.ipv6.proto.mask[0] =
586 match.mask->ip_proto;
587 match_protocol = false;
588 }
589 }
590
591 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS) &&
592 proto == ETH_P_IP) {
593 struct flow_match_ipv4_addrs match;
594 u8 *tmp;
595
596 if (filter->block_id == VCAP_ES0) {
597 NL_SET_ERR_MSG_MOD(extack,
598 "VCAP ES0 cannot match on IP address");
599 return -EOPNOTSUPP;
600 }
601
602 flow_rule_match_ipv4_addrs(rule, &match);
603
604 if (filter->block_id == VCAP_IS1 && *(u32 *)&match.mask->dst) {
605 NL_SET_ERR_MSG_MOD(extack,
606 "Key type S1_NORMAL cannot match on destination IP");
607 return -EOPNOTSUPP;
608 }
609
610 tmp = &filter->key.ipv4.sip.value.addr[0];
611 memcpy(tmp, &match.key->src, 4);
612
613 tmp = &filter->key.ipv4.sip.mask.addr[0];
614 memcpy(tmp, &match.mask->src, 4);
615
616 tmp = &filter->key.ipv4.dip.value.addr[0];
617 memcpy(tmp, &match.key->dst, 4);
618
619 tmp = &filter->key.ipv4.dip.mask.addr[0];
620 memcpy(tmp, &match.mask->dst, 4);
621 match_protocol = false;
622 }
623
624 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS) &&
625 proto == ETH_P_IPV6) {
626 return -EOPNOTSUPP;
627 }
628
629 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
630 struct flow_match_ports match;
631
632 if (filter->block_id == VCAP_ES0) {
633 NL_SET_ERR_MSG_MOD(extack,
634 "VCAP ES0 cannot match on L4 ports");
635 return -EOPNOTSUPP;
636 }
637
638 flow_rule_match_ports(rule, &match);
639 filter->key.ipv4.sport.value = ntohs(match.key->src);
640 filter->key.ipv4.sport.mask = ntohs(match.mask->src);
641 filter->key.ipv4.dport.value = ntohs(match.key->dst);
642 filter->key.ipv4.dport.mask = ntohs(match.mask->dst);
643 match_protocol = false;
644 }
645
646 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
647 struct flow_match_vlan match;
648
649 flow_rule_match_vlan(rule, &match);
650 filter->key_type = OCELOT_VCAP_KEY_ANY;
651 filter->vlan.vid.value = match.key->vlan_id;
652 filter->vlan.vid.mask = match.mask->vlan_id;
653 filter->vlan.pcp.value[0] = match.key->vlan_priority;
654 filter->vlan.pcp.mask[0] = match.mask->vlan_priority;
655 match_protocol = false;
656 }
657
658 finished_key_parsing:
659 if (match_protocol && proto != ETH_P_ALL) {
660 if (filter->block_id == VCAP_ES0) {
661 NL_SET_ERR_MSG_MOD(extack,
662 "VCAP ES0 cannot match on L2 proto");
663 return -EOPNOTSUPP;
664 }
665
666 /* TODO: support SNAP, LLC etc */
667 if (proto < ETH_P_802_3_MIN)
668 return -EOPNOTSUPP;
669 filter->key_type = OCELOT_VCAP_KEY_ETYPE;
670 *(__be16 *)filter->key.etype.etype.value = htons(proto);
671 *(__be16 *)filter->key.etype.etype.mask = htons(0xffff);
672 }
673 /* else, a filter of type OCELOT_VCAP_KEY_ANY is implicitly added */
674
675 return 0;
676 }
677
ocelot_flower_parse(struct ocelot * ocelot,int port,bool ingress,struct flow_cls_offload * f,struct ocelot_vcap_filter * filter)678 static int ocelot_flower_parse(struct ocelot *ocelot, int port, bool ingress,
679 struct flow_cls_offload *f,
680 struct ocelot_vcap_filter *filter)
681 {
682 int ret;
683
684 filter->prio = f->common.prio;
685 filter->id.cookie = f->cookie;
686 filter->id.tc_offload = true;
687
688 ret = ocelot_flower_parse_action(ocelot, port, ingress, f, filter);
689 if (ret)
690 return ret;
691
692 return ocelot_flower_parse_key(ocelot, port, ingress, f, filter);
693 }
694
695 static struct ocelot_vcap_filter
ocelot_vcap_filter_create(struct ocelot * ocelot,int port,bool ingress,struct flow_cls_offload * f)696 *ocelot_vcap_filter_create(struct ocelot *ocelot, int port, bool ingress,
697 struct flow_cls_offload *f)
698 {
699 struct ocelot_vcap_filter *filter;
700
701 filter = kzalloc(sizeof(*filter), GFP_KERNEL);
702 if (!filter)
703 return NULL;
704
705 if (ingress) {
706 filter->ingress_port_mask = BIT(port);
707 } else {
708 const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0];
709 int key_length = vcap->keys[VCAP_ES0_EGR_PORT].length;
710
711 filter->egress_port.value = port;
712 filter->egress_port.mask = GENMASK(key_length - 1, 0);
713 }
714
715 return filter;
716 }
717
ocelot_vcap_dummy_filter_add(struct ocelot * ocelot,struct ocelot_vcap_filter * filter)718 static int ocelot_vcap_dummy_filter_add(struct ocelot *ocelot,
719 struct ocelot_vcap_filter *filter)
720 {
721 list_add(&filter->list, &ocelot->dummy_rules);
722
723 return 0;
724 }
725
ocelot_vcap_dummy_filter_del(struct ocelot * ocelot,struct ocelot_vcap_filter * filter)726 static int ocelot_vcap_dummy_filter_del(struct ocelot *ocelot,
727 struct ocelot_vcap_filter *filter)
728 {
729 list_del(&filter->list);
730 kfree(filter);
731
732 return 0;
733 }
734
735 /* If we have an egress VLAN modification rule, we need to actually write the
736 * delta between the input VLAN (from the key) and the output VLAN (from the
737 * action), but the action was parsed first. So we need to patch the delta into
738 * the action here.
739 */
740 static int
ocelot_flower_patch_es0_vlan_modify(struct ocelot_vcap_filter * filter,struct netlink_ext_ack * extack)741 ocelot_flower_patch_es0_vlan_modify(struct ocelot_vcap_filter *filter,
742 struct netlink_ext_ack *extack)
743 {
744 if (filter->block_id != VCAP_ES0 ||
745 filter->action.tag_a_vid_sel != OCELOT_ES0_VID_PLUS_CLASSIFIED_VID)
746 return 0;
747
748 if (filter->vlan.vid.mask != VLAN_VID_MASK) {
749 NL_SET_ERR_MSG_MOD(extack,
750 "VCAP ES0 VLAN rewriting needs a full VLAN in the key");
751 return -EOPNOTSUPP;
752 }
753
754 filter->action.vid_a_val -= filter->vlan.vid.value;
755 filter->action.vid_a_val &= VLAN_VID_MASK;
756
757 return 0;
758 }
759
ocelot_cls_flower_replace(struct ocelot * ocelot,int port,struct flow_cls_offload * f,bool ingress)760 int ocelot_cls_flower_replace(struct ocelot *ocelot, int port,
761 struct flow_cls_offload *f, bool ingress)
762 {
763 struct netlink_ext_ack *extack = f->common.extack;
764 struct ocelot_vcap_filter *filter;
765 int chain = f->common.chain_index;
766 int ret;
767
768 if (chain && !ocelot_find_vcap_filter_that_points_at(ocelot, chain)) {
769 NL_SET_ERR_MSG_MOD(extack, "No default GOTO action points to this chain");
770 return -EOPNOTSUPP;
771 }
772
773 filter = ocelot_vcap_filter_create(ocelot, port, ingress, f);
774 if (!filter)
775 return -ENOMEM;
776
777 ret = ocelot_flower_parse(ocelot, port, ingress, f, filter);
778 if (ret) {
779 kfree(filter);
780 return ret;
781 }
782
783 ret = ocelot_flower_patch_es0_vlan_modify(filter, extack);
784 if (ret) {
785 kfree(filter);
786 return ret;
787 }
788
789 /* The non-optional GOTOs for the TCAM skeleton don't need
790 * to be actually offloaded.
791 */
792 if (filter->type == OCELOT_VCAP_FILTER_DUMMY)
793 return ocelot_vcap_dummy_filter_add(ocelot, filter);
794
795 return ocelot_vcap_filter_add(ocelot, filter, f->common.extack);
796 }
797 EXPORT_SYMBOL_GPL(ocelot_cls_flower_replace);
798
ocelot_cls_flower_destroy(struct ocelot * ocelot,int port,struct flow_cls_offload * f,bool ingress)799 int ocelot_cls_flower_destroy(struct ocelot *ocelot, int port,
800 struct flow_cls_offload *f, bool ingress)
801 {
802 struct ocelot_vcap_filter *filter;
803 struct ocelot_vcap_block *block;
804 int block_id;
805
806 block_id = ocelot_chain_to_block(f->common.chain_index, ingress);
807 if (block_id < 0)
808 return 0;
809
810 block = &ocelot->block[block_id];
811
812 filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true);
813 if (!filter)
814 return 0;
815
816 if (filter->type == OCELOT_VCAP_FILTER_DUMMY)
817 return ocelot_vcap_dummy_filter_del(ocelot, filter);
818
819 return ocelot_vcap_filter_del(ocelot, filter);
820 }
821 EXPORT_SYMBOL_GPL(ocelot_cls_flower_destroy);
822
ocelot_cls_flower_stats(struct ocelot * ocelot,int port,struct flow_cls_offload * f,bool ingress)823 int ocelot_cls_flower_stats(struct ocelot *ocelot, int port,
824 struct flow_cls_offload *f, bool ingress)
825 {
826 struct ocelot_vcap_filter *filter;
827 struct ocelot_vcap_block *block;
828 int block_id, ret;
829
830 block_id = ocelot_chain_to_block(f->common.chain_index, ingress);
831 if (block_id < 0)
832 return 0;
833
834 block = &ocelot->block[block_id];
835
836 filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true);
837 if (!filter || filter->type == OCELOT_VCAP_FILTER_DUMMY)
838 return 0;
839
840 ret = ocelot_vcap_filter_stats_update(ocelot, filter);
841 if (ret)
842 return ret;
843
844 flow_stats_update(&f->stats, 0x0, filter->stats.pkts, 0, 0x0,
845 FLOW_ACTION_HW_STATS_IMMEDIATE);
846 return 0;
847 }
848 EXPORT_SYMBOL_GPL(ocelot_cls_flower_stats);
849