Loading...
Note: File does not exist in v3.15.
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_police.h"
10#include "ocelot_vcap.h"
11
12/* Arbitrarily chosen constants for encoding the VCAP block and lookup number
13 * into the chain number. This is UAPI.
14 */
15#define VCAP_BLOCK 10000
16#define VCAP_LOOKUP 1000
17#define VCAP_IS1_NUM_LOOKUPS 3
18#define VCAP_IS2_NUM_LOOKUPS 2
19#define VCAP_IS2_NUM_PAG 256
20#define VCAP_IS1_CHAIN(lookup) \
21 (1 * VCAP_BLOCK + (lookup) * VCAP_LOOKUP)
22#define VCAP_IS2_CHAIN(lookup, pag) \
23 (2 * VCAP_BLOCK + (lookup) * VCAP_LOOKUP + (pag))
24/* PSFP chain and block ID */
25#define PSFP_BLOCK_ID OCELOT_NUM_VCAP_BLOCKS
26#define OCELOT_PSFP_CHAIN (3 * VCAP_BLOCK)
27
28static int ocelot_chain_to_block(int chain, bool ingress)
29{
30 int lookup, pag;
31
32 if (!ingress) {
33 if (chain == 0)
34 return VCAP_ES0;
35 return -EOPNOTSUPP;
36 }
37
38 /* Backwards compatibility with older, single-chain tc-flower
39 * offload support in Ocelot
40 */
41 if (chain == 0)
42 return VCAP_IS2;
43
44 for (lookup = 0; lookup < VCAP_IS1_NUM_LOOKUPS; lookup++)
45 if (chain == VCAP_IS1_CHAIN(lookup))
46 return VCAP_IS1;
47
48 for (lookup = 0; lookup < VCAP_IS2_NUM_LOOKUPS; lookup++)
49 for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++)
50 if (chain == VCAP_IS2_CHAIN(lookup, pag))
51 return VCAP_IS2;
52
53 if (chain == OCELOT_PSFP_CHAIN)
54 return PSFP_BLOCK_ID;
55
56 return -EOPNOTSUPP;
57}
58
59/* Caller must ensure this is a valid IS1 or IS2 chain first,
60 * by calling ocelot_chain_to_block.
61 */
62static int ocelot_chain_to_lookup(int chain)
63{
64 /* Backwards compatibility with older, single-chain tc-flower
65 * offload support in Ocelot
66 */
67 if (chain == 0)
68 return 0;
69
70 return (chain / VCAP_LOOKUP) % 10;
71}
72
73/* Caller must ensure this is a valid IS2 chain first,
74 * by calling ocelot_chain_to_block.
75 */
76static int ocelot_chain_to_pag(int chain)
77{
78 int lookup;
79
80 /* Backwards compatibility with older, single-chain tc-flower
81 * offload support in Ocelot
82 */
83 if (chain == 0)
84 return 0;
85
86 lookup = ocelot_chain_to_lookup(chain);
87
88 /* calculate PAG value as chain index relative to the first PAG */
89 return chain - VCAP_IS2_CHAIN(lookup, 0);
90}
91
92static bool ocelot_is_goto_target_valid(int goto_target, int chain,
93 bool ingress)
94{
95 int pag;
96
97 /* Can't offload GOTO in VCAP ES0 */
98 if (!ingress)
99 return (goto_target < 0);
100
101 /* Non-optional GOTOs */
102 if (chain == 0)
103 /* VCAP IS1 can be skipped, either partially or completely */
104 return (goto_target == VCAP_IS1_CHAIN(0) ||
105 goto_target == VCAP_IS1_CHAIN(1) ||
106 goto_target == VCAP_IS1_CHAIN(2) ||
107 goto_target == VCAP_IS2_CHAIN(0, 0) ||
108 goto_target == VCAP_IS2_CHAIN(1, 0) ||
109 goto_target == OCELOT_PSFP_CHAIN);
110
111 if (chain == VCAP_IS1_CHAIN(0))
112 return (goto_target == VCAP_IS1_CHAIN(1));
113
114 if (chain == VCAP_IS1_CHAIN(1))
115 return (goto_target == VCAP_IS1_CHAIN(2));
116
117 /* Lookup 2 of VCAP IS1 can really support non-optional GOTOs,
118 * using a Policy Association Group (PAG) value, which is an 8-bit
119 * value encoding a VCAP IS2 target chain.
120 */
121 if (chain == VCAP_IS1_CHAIN(2)) {
122 for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++)
123 if (goto_target == VCAP_IS2_CHAIN(0, pag))
124 return true;
125
126 return false;
127 }
128
129 /* Non-optional GOTO from VCAP IS2 lookup 0 to lookup 1.
130 * We cannot change the PAG at this point.
131 */
132 for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++)
133 if (chain == VCAP_IS2_CHAIN(0, pag))
134 return (goto_target == VCAP_IS2_CHAIN(1, pag));
135
136 /* VCAP IS2 lookup 1 can goto to PSFP block if hardware support */
137 for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++)
138 if (chain == VCAP_IS2_CHAIN(1, pag))
139 return (goto_target == OCELOT_PSFP_CHAIN);
140
141 return false;
142}
143
144static struct ocelot_vcap_filter *
145ocelot_find_vcap_filter_that_points_at(struct ocelot *ocelot, int chain)
146{
147 struct ocelot_vcap_filter *filter;
148 struct ocelot_vcap_block *block;
149 int block_id;
150
151 block_id = ocelot_chain_to_block(chain, true);
152 if (block_id < 0)
153 return NULL;
154
155 if (block_id == VCAP_IS2) {
156 block = &ocelot->block[VCAP_IS1];
157
158 list_for_each_entry(filter, &block->rules, list)
159 if (filter->type == OCELOT_VCAP_FILTER_PAG &&
160 filter->goto_target == chain)
161 return filter;
162 }
163
164 list_for_each_entry(filter, &ocelot->dummy_rules, list)
165 if (filter->goto_target == chain)
166 return filter;
167
168 return NULL;
169}
170
171static int
172ocelot_flower_parse_ingress_vlan_modify(struct ocelot *ocelot, int port,
173 struct ocelot_vcap_filter *filter,
174 const struct flow_action_entry *a,
175 struct netlink_ext_ack *extack)
176{
177 struct ocelot_port *ocelot_port = ocelot->ports[port];
178
179 if (filter->goto_target != -1) {
180 NL_SET_ERR_MSG_MOD(extack,
181 "Last action must be GOTO");
182 return -EOPNOTSUPP;
183 }
184
185 if (!ocelot_port->vlan_aware) {
186 NL_SET_ERR_MSG_MOD(extack,
187 "Can only modify VLAN under VLAN aware bridge");
188 return -EOPNOTSUPP;
189 }
190
191 filter->action.vid_replace_ena = true;
192 filter->action.pcp_dei_ena = true;
193 filter->action.vid = a->vlan.vid;
194 filter->action.pcp = a->vlan.prio;
195 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
196
197 return 0;
198}
199
200static int
201ocelot_flower_parse_egress_vlan_modify(struct ocelot_vcap_filter *filter,
202 const struct flow_action_entry *a,
203 struct netlink_ext_ack *extack)
204{
205 enum ocelot_tag_tpid_sel tpid;
206
207 switch (ntohs(a->vlan.proto)) {
208 case ETH_P_8021Q:
209 tpid = OCELOT_TAG_TPID_SEL_8021Q;
210 break;
211 case ETH_P_8021AD:
212 tpid = OCELOT_TAG_TPID_SEL_8021AD;
213 break;
214 default:
215 NL_SET_ERR_MSG_MOD(extack,
216 "Cannot modify custom TPID");
217 return -EOPNOTSUPP;
218 }
219
220 filter->action.tag_a_tpid_sel = tpid;
221 filter->action.push_outer_tag = OCELOT_ES0_TAG;
222 filter->action.tag_a_vid_sel = OCELOT_ES0_VID_PLUS_CLASSIFIED_VID;
223 filter->action.vid_a_val = a->vlan.vid;
224 filter->action.pcp_a_val = a->vlan.prio;
225 filter->action.tag_a_pcp_sel = OCELOT_ES0_PCP;
226 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
227
228 return 0;
229}
230
231static int
232ocelot_flower_parse_egress_port(struct ocelot *ocelot, struct flow_cls_offload *f,
233 const struct flow_action_entry *a, bool mirror,
234 struct netlink_ext_ack *extack)
235{
236 const char *act_string = mirror ? "mirror" : "redirect";
237 int egress_port = ocelot->ops->netdev_to_port(a->dev);
238 enum flow_action_id offloadable_act_id;
239
240 offloadable_act_id = mirror ? FLOW_ACTION_MIRRED : FLOW_ACTION_REDIRECT;
241
242 /* Mirroring towards foreign interfaces is handled in software */
243 if (egress_port < 0 || a->id != offloadable_act_id) {
244 if (f->common.skip_sw) {
245 NL_SET_ERR_MSG_FMT(extack,
246 "Can only %s to %s if filter also runs in software",
247 act_string, egress_port < 0 ?
248 "CPU" : "ingress of ocelot port");
249 return -EOPNOTSUPP;
250 }
251 egress_port = ocelot->num_phys_ports;
252 }
253
254 return egress_port;
255}
256
257static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
258 bool ingress, struct flow_cls_offload *f,
259 struct ocelot_vcap_filter *filter)
260{
261 const struct flow_action *action = &f->rule->action;
262 struct netlink_ext_ack *extack = f->common.extack;
263 bool allow_missing_goto_target = false;
264 const struct flow_action_entry *a;
265 enum ocelot_tag_tpid_sel tpid;
266 int i, chain, egress_port;
267 u32 pol_ix, pol_max;
268 u64 rate;
269 int err;
270
271 if (!flow_action_basic_hw_stats_check(&f->rule->action,
272 f->common.extack))
273 return -EOPNOTSUPP;
274
275 chain = f->common.chain_index;
276 filter->block_id = ocelot_chain_to_block(chain, ingress);
277 if (filter->block_id < 0) {
278 NL_SET_ERR_MSG_MOD(extack, "Cannot offload to this chain");
279 return -EOPNOTSUPP;
280 }
281 if (filter->block_id == VCAP_IS1 || filter->block_id == VCAP_IS2)
282 filter->lookup = ocelot_chain_to_lookup(chain);
283 if (filter->block_id == VCAP_IS2)
284 filter->pag = ocelot_chain_to_pag(chain);
285
286 filter->goto_target = -1;
287 filter->type = OCELOT_VCAP_FILTER_DUMMY;
288
289 flow_action_for_each(i, a, action) {
290 switch (a->id) {
291 case FLOW_ACTION_DROP:
292 if (filter->block_id != VCAP_IS2) {
293 NL_SET_ERR_MSG_MOD(extack,
294 "Drop action can only be offloaded to VCAP IS2");
295 return -EOPNOTSUPP;
296 }
297 if (filter->goto_target != -1) {
298 NL_SET_ERR_MSG_MOD(extack,
299 "Last action must be GOTO");
300 return -EOPNOTSUPP;
301 }
302 filter->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY;
303 filter->action.port_mask = 0;
304 filter->action.police_ena = true;
305 filter->action.pol_ix = OCELOT_POLICER_DISCARD;
306 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
307 break;
308 case FLOW_ACTION_ACCEPT:
309 if (filter->block_id != VCAP_ES0 &&
310 filter->block_id != VCAP_IS1 &&
311 filter->block_id != VCAP_IS2) {
312 NL_SET_ERR_MSG_MOD(extack,
313 "Accept action can only be offloaded to VCAP chains");
314 return -EOPNOTSUPP;
315 }
316 if (filter->block_id != VCAP_ES0 &&
317 filter->goto_target != -1) {
318 NL_SET_ERR_MSG_MOD(extack,
319 "Last action must be GOTO");
320 return -EOPNOTSUPP;
321 }
322 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
323 break;
324 case FLOW_ACTION_TRAP:
325 if (filter->block_id != VCAP_IS2 ||
326 filter->lookup != 0) {
327 NL_SET_ERR_MSG_MOD(extack,
328 "Trap action can only be offloaded to VCAP IS2 lookup 0");
329 return -EOPNOTSUPP;
330 }
331 if (filter->goto_target != -1) {
332 NL_SET_ERR_MSG_MOD(extack,
333 "Last action must be GOTO");
334 return -EOPNOTSUPP;
335 }
336 filter->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY;
337 filter->action.port_mask = 0;
338 filter->action.cpu_copy_ena = true;
339 filter->action.cpu_qu_num = 0;
340 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
341 filter->is_trap = true;
342 break;
343 case FLOW_ACTION_POLICE:
344 if (filter->block_id == PSFP_BLOCK_ID) {
345 filter->type = OCELOT_PSFP_FILTER_OFFLOAD;
346 break;
347 }
348 if (filter->block_id != VCAP_IS2 ||
349 filter->lookup != 0) {
350 NL_SET_ERR_MSG_MOD(extack,
351 "Police action can only be offloaded to VCAP IS2 lookup 0 or PSFP");
352 return -EOPNOTSUPP;
353 }
354 if (filter->goto_target != -1) {
355 NL_SET_ERR_MSG_MOD(extack,
356 "Last action must be GOTO");
357 return -EOPNOTSUPP;
358 }
359
360 err = ocelot_policer_validate(action, a, extack);
361 if (err)
362 return err;
363
364 filter->action.police_ena = true;
365
366 pol_ix = a->hw_index + ocelot->vcap_pol.base;
367 pol_max = ocelot->vcap_pol.max;
368
369 if (ocelot->vcap_pol.max2 && pol_ix > pol_max) {
370 pol_ix += ocelot->vcap_pol.base2 - pol_max - 1;
371 pol_max = ocelot->vcap_pol.max2;
372 }
373
374 if (pol_ix >= pol_max)
375 return -EINVAL;
376
377 filter->action.pol_ix = pol_ix;
378
379 rate = a->police.rate_bytes_ps;
380 filter->action.pol.rate = div_u64(rate, 1000) * 8;
381 filter->action.pol.burst = a->police.burst;
382 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
383 break;
384 case FLOW_ACTION_REDIRECT:
385 case FLOW_ACTION_REDIRECT_INGRESS:
386 if (filter->block_id != VCAP_IS2) {
387 NL_SET_ERR_MSG_MOD(extack,
388 "Redirect action can only be offloaded to VCAP IS2");
389 return -EOPNOTSUPP;
390 }
391 if (filter->goto_target != -1) {
392 NL_SET_ERR_MSG_MOD(extack,
393 "Last action must be GOTO");
394 return -EOPNOTSUPP;
395 }
396
397 egress_port = ocelot_flower_parse_egress_port(ocelot, f,
398 a, false,
399 extack);
400 if (egress_port < 0)
401 return egress_port;
402
403 filter->action.mask_mode = OCELOT_MASK_MODE_REDIRECT;
404 filter->action.port_mask = BIT(egress_port);
405 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
406 break;
407 case FLOW_ACTION_MIRRED:
408 case FLOW_ACTION_MIRRED_INGRESS:
409 if (filter->block_id != VCAP_IS2) {
410 NL_SET_ERR_MSG_MOD(extack,
411 "Mirror action can only be offloaded to VCAP IS2");
412 return -EOPNOTSUPP;
413 }
414 if (filter->goto_target != -1) {
415 NL_SET_ERR_MSG_MOD(extack,
416 "Last action must be GOTO");
417 return -EOPNOTSUPP;
418 }
419
420 egress_port = ocelot_flower_parse_egress_port(ocelot, f,
421 a, true,
422 extack);
423 if (egress_port < 0)
424 return egress_port;
425
426 filter->egress_port.value = egress_port;
427 filter->action.mirror_ena = true;
428 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
429 break;
430 case FLOW_ACTION_VLAN_POP:
431 if (filter->block_id != VCAP_IS1) {
432 NL_SET_ERR_MSG_MOD(extack,
433 "VLAN pop action can only be offloaded to VCAP IS1");
434 return -EOPNOTSUPP;
435 }
436 if (filter->goto_target != -1) {
437 NL_SET_ERR_MSG_MOD(extack,
438 "Last action must be GOTO");
439 return -EOPNOTSUPP;
440 }
441 filter->action.vlan_pop_cnt_ena = true;
442 filter->action.vlan_pop_cnt++;
443 if (filter->action.vlan_pop_cnt > 2) {
444 NL_SET_ERR_MSG_MOD(extack,
445 "Cannot pop more than 2 VLAN headers");
446 return -EOPNOTSUPP;
447 }
448 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
449 break;
450 case FLOW_ACTION_VLAN_MANGLE:
451 if (filter->block_id == VCAP_IS1) {
452 err = ocelot_flower_parse_ingress_vlan_modify(ocelot, port,
453 filter, a,
454 extack);
455 } else if (filter->block_id == VCAP_ES0) {
456 err = ocelot_flower_parse_egress_vlan_modify(filter, a,
457 extack);
458 } else {
459 NL_SET_ERR_MSG_MOD(extack,
460 "VLAN modify action can only be offloaded to VCAP IS1 or ES0");
461 err = -EOPNOTSUPP;
462 }
463 if (err)
464 return err;
465 break;
466 case FLOW_ACTION_PRIORITY:
467 if (filter->block_id != VCAP_IS1) {
468 NL_SET_ERR_MSG_MOD(extack,
469 "Priority action can only be offloaded to VCAP IS1");
470 return -EOPNOTSUPP;
471 }
472 if (filter->goto_target != -1) {
473 NL_SET_ERR_MSG_MOD(extack,
474 "Last action must be GOTO");
475 return -EOPNOTSUPP;
476 }
477 filter->action.qos_ena = true;
478 filter->action.qos_val = a->priority;
479 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
480 break;
481 case FLOW_ACTION_GOTO:
482 filter->goto_target = a->chain_index;
483
484 if (filter->block_id == VCAP_IS1 && filter->lookup == 2) {
485 int pag = ocelot_chain_to_pag(filter->goto_target);
486
487 filter->action.pag_override_mask = 0xff;
488 filter->action.pag_val = pag;
489 filter->type = OCELOT_VCAP_FILTER_PAG;
490 }
491 break;
492 case FLOW_ACTION_VLAN_PUSH:
493 if (filter->block_id != VCAP_ES0) {
494 NL_SET_ERR_MSG_MOD(extack,
495 "VLAN push action can only be offloaded to VCAP ES0");
496 return -EOPNOTSUPP;
497 }
498 switch (ntohs(a->vlan.proto)) {
499 case ETH_P_8021Q:
500 tpid = OCELOT_TAG_TPID_SEL_8021Q;
501 break;
502 case ETH_P_8021AD:
503 tpid = OCELOT_TAG_TPID_SEL_8021AD;
504 break;
505 default:
506 NL_SET_ERR_MSG_MOD(extack,
507 "Cannot push custom TPID");
508 return -EOPNOTSUPP;
509 }
510 filter->action.tag_a_tpid_sel = tpid;
511 filter->action.push_outer_tag = OCELOT_ES0_TAG;
512 filter->action.tag_a_vid_sel = OCELOT_ES0_VID;
513 filter->action.vid_a_val = a->vlan.vid;
514 filter->action.pcp_a_val = a->vlan.prio;
515 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
516 break;
517 case FLOW_ACTION_GATE:
518 if (filter->block_id != PSFP_BLOCK_ID) {
519 NL_SET_ERR_MSG_MOD(extack,
520 "Gate action can only be offloaded to PSFP chain");
521 return -EOPNOTSUPP;
522 }
523 filter->type = OCELOT_PSFP_FILTER_OFFLOAD;
524 break;
525 default:
526 NL_SET_ERR_MSG_MOD(extack, "Cannot offload action");
527 return -EOPNOTSUPP;
528 }
529 }
530
531 if (filter->goto_target == -1) {
532 if ((filter->block_id == VCAP_IS2 && filter->lookup == 1) ||
533 chain == 0 || filter->block_id == PSFP_BLOCK_ID) {
534 allow_missing_goto_target = true;
535 } else {
536 NL_SET_ERR_MSG_MOD(extack, "Missing GOTO action");
537 return -EOPNOTSUPP;
538 }
539 }
540
541 if (!ocelot_is_goto_target_valid(filter->goto_target, chain, ingress) &&
542 !allow_missing_goto_target) {
543 NL_SET_ERR_MSG_MOD(extack, "Cannot offload this GOTO target");
544 return -EOPNOTSUPP;
545 }
546
547 return 0;
548}
549
550static int ocelot_flower_parse_indev(struct ocelot *ocelot, int port,
551 struct flow_cls_offload *f,
552 struct ocelot_vcap_filter *filter)
553{
554 struct flow_rule *rule = flow_cls_offload_flow_rule(f);
555 const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0];
556 int key_length = vcap->keys[VCAP_ES0_IGR_PORT].length;
557 struct netlink_ext_ack *extack = f->common.extack;
558 struct net_device *dev, *indev;
559 struct flow_match_meta match;
560 int ingress_port;
561
562 flow_rule_match_meta(rule, &match);
563
564 if (!match.mask->ingress_ifindex)
565 return 0;
566
567 if (match.mask->ingress_ifindex != 0xFFFFFFFF) {
568 NL_SET_ERR_MSG_MOD(extack, "Unsupported ingress ifindex mask");
569 return -EOPNOTSUPP;
570 }
571
572 dev = ocelot->ops->port_to_netdev(ocelot, port);
573 if (!dev)
574 return -EINVAL;
575
576 indev = __dev_get_by_index(dev_net(dev), match.key->ingress_ifindex);
577 if (!indev) {
578 NL_SET_ERR_MSG_MOD(extack,
579 "Can't find the ingress port to match on");
580 return -ENOENT;
581 }
582
583 ingress_port = ocelot->ops->netdev_to_port(indev);
584 if (ingress_port < 0) {
585 NL_SET_ERR_MSG_MOD(extack,
586 "Can only offload an ocelot ingress port");
587 return -EOPNOTSUPP;
588 }
589 if (ingress_port == port) {
590 NL_SET_ERR_MSG_MOD(extack,
591 "Ingress port is equal to the egress port");
592 return -EINVAL;
593 }
594
595 filter->ingress_port.value = ingress_port;
596 filter->ingress_port.mask = GENMASK(key_length - 1, 0);
597
598 return 0;
599}
600
601static int
602ocelot_flower_parse_key(struct ocelot *ocelot, int port, bool ingress,
603 struct flow_cls_offload *f,
604 struct ocelot_vcap_filter *filter)
605{
606 struct flow_rule *rule = flow_cls_offload_flow_rule(f);
607 struct flow_dissector *dissector = rule->match.dissector;
608 struct netlink_ext_ack *extack = f->common.extack;
609 u16 proto = ntohs(f->common.protocol);
610 bool match_protocol = true;
611 int ret;
612
613 if (dissector->used_keys &
614 ~(BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) |
615 BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
616 BIT_ULL(FLOW_DISSECTOR_KEY_META) |
617 BIT_ULL(FLOW_DISSECTOR_KEY_PORTS) |
618 BIT_ULL(FLOW_DISSECTOR_KEY_VLAN) |
619 BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
620 BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
621 BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
622 return -EOPNOTSUPP;
623 }
624
625 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_META)) {
626 struct flow_match_meta match;
627
628 flow_rule_match_meta(rule, &match);
629 if (match.mask->l2_miss) {
630 NL_SET_ERR_MSG_MOD(extack, "Can't match on \"l2_miss\"");
631 return -EOPNOTSUPP;
632 }
633 }
634
635 /* For VCAP ES0 (egress rewriter) we can match on the ingress port */
636 if (!ingress) {
637 ret = ocelot_flower_parse_indev(ocelot, port, f, filter);
638 if (ret)
639 return ret;
640 }
641
642 if (flow_rule_match_has_control_flags(rule, extack))
643 return -EOPNOTSUPP;
644
645 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
646 struct flow_match_vlan match;
647
648 flow_rule_match_vlan(rule, &match);
649 filter->key_type = OCELOT_VCAP_KEY_ANY;
650 filter->vlan.vid.value = match.key->vlan_id;
651 filter->vlan.vid.mask = match.mask->vlan_id;
652 filter->vlan.pcp.value[0] = match.key->vlan_priority;
653 filter->vlan.pcp.mask[0] = match.mask->vlan_priority;
654 match_protocol = false;
655 }
656
657 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
658 struct flow_match_eth_addrs match;
659
660 if (filter->block_id == VCAP_ES0) {
661 NL_SET_ERR_MSG_MOD(extack,
662 "VCAP ES0 cannot match on MAC address");
663 return -EOPNOTSUPP;
664 }
665
666 /* The hw support mac matches only for MAC_ETYPE key,
667 * therefore if other matches(port, tcp flags, etc) are added
668 * then just bail out
669 */
670 if ((dissector->used_keys &
671 (BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
672 BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
673 BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL))) !=
674 (BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
675 BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
676 BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL)))
677 return -EOPNOTSUPP;
678
679 flow_rule_match_eth_addrs(rule, &match);
680
681 if (filter->block_id == VCAP_IS1 &&
682 !is_zero_ether_addr(match.mask->dst)) {
683 NL_SET_ERR_MSG_MOD(extack,
684 "Key type S1_NORMAL cannot match on destination MAC");
685 return -EOPNOTSUPP;
686 }
687
688 filter->key_type = OCELOT_VCAP_KEY_ETYPE;
689 ether_addr_copy(filter->key.etype.dmac.value,
690 match.key->dst);
691 ether_addr_copy(filter->key.etype.smac.value,
692 match.key->src);
693 ether_addr_copy(filter->key.etype.dmac.mask,
694 match.mask->dst);
695 ether_addr_copy(filter->key.etype.smac.mask,
696 match.mask->src);
697 goto finished_key_parsing;
698 }
699
700 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
701 struct flow_match_basic match;
702
703 flow_rule_match_basic(rule, &match);
704 if (ntohs(match.key->n_proto) == ETH_P_IP) {
705 if (filter->block_id == VCAP_ES0) {
706 NL_SET_ERR_MSG_MOD(extack,
707 "VCAP ES0 cannot match on IP protocol");
708 return -EOPNOTSUPP;
709 }
710
711 filter->key_type = OCELOT_VCAP_KEY_IPV4;
712 filter->key.ipv4.proto.value[0] =
713 match.key->ip_proto;
714 filter->key.ipv4.proto.mask[0] =
715 match.mask->ip_proto;
716 match_protocol = false;
717 }
718 if (ntohs(match.key->n_proto) == ETH_P_IPV6) {
719 if (filter->block_id == VCAP_ES0) {
720 NL_SET_ERR_MSG_MOD(extack,
721 "VCAP ES0 cannot match on IP protocol");
722 return -EOPNOTSUPP;
723 }
724
725 filter->key_type = OCELOT_VCAP_KEY_IPV6;
726 filter->key.ipv6.proto.value[0] =
727 match.key->ip_proto;
728 filter->key.ipv6.proto.mask[0] =
729 match.mask->ip_proto;
730 match_protocol = false;
731 }
732 }
733
734 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS) &&
735 proto == ETH_P_IP) {
736 struct flow_match_ipv4_addrs match;
737 u8 *tmp;
738
739 if (filter->block_id == VCAP_ES0) {
740 NL_SET_ERR_MSG_MOD(extack,
741 "VCAP ES0 cannot match on IP address");
742 return -EOPNOTSUPP;
743 }
744
745 flow_rule_match_ipv4_addrs(rule, &match);
746
747 if (filter->block_id == VCAP_IS1 && *(u32 *)&match.mask->dst) {
748 NL_SET_ERR_MSG_MOD(extack,
749 "Key type S1_NORMAL cannot match on destination IP");
750 return -EOPNOTSUPP;
751 }
752
753 tmp = &filter->key.ipv4.sip.value.addr[0];
754 memcpy(tmp, &match.key->src, 4);
755
756 tmp = &filter->key.ipv4.sip.mask.addr[0];
757 memcpy(tmp, &match.mask->src, 4);
758
759 tmp = &filter->key.ipv4.dip.value.addr[0];
760 memcpy(tmp, &match.key->dst, 4);
761
762 tmp = &filter->key.ipv4.dip.mask.addr[0];
763 memcpy(tmp, &match.mask->dst, 4);
764 match_protocol = false;
765 }
766
767 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS) &&
768 proto == ETH_P_IPV6) {
769 return -EOPNOTSUPP;
770 }
771
772 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
773 struct flow_match_ports match;
774
775 if (filter->block_id == VCAP_ES0) {
776 NL_SET_ERR_MSG_MOD(extack,
777 "VCAP ES0 cannot match on L4 ports");
778 return -EOPNOTSUPP;
779 }
780
781 flow_rule_match_ports(rule, &match);
782 filter->key.ipv4.sport.value = ntohs(match.key->src);
783 filter->key.ipv4.sport.mask = ntohs(match.mask->src);
784 filter->key.ipv4.dport.value = ntohs(match.key->dst);
785 filter->key.ipv4.dport.mask = ntohs(match.mask->dst);
786 match_protocol = false;
787 }
788
789finished_key_parsing:
790 if (match_protocol && proto != ETH_P_ALL) {
791 if (filter->block_id == VCAP_ES0) {
792 NL_SET_ERR_MSG_MOD(extack,
793 "VCAP ES0 cannot match on L2 proto");
794 return -EOPNOTSUPP;
795 }
796
797 /* TODO: support SNAP, LLC etc */
798 if (proto < ETH_P_802_3_MIN)
799 return -EOPNOTSUPP;
800 filter->key_type = OCELOT_VCAP_KEY_ETYPE;
801 *(__be16 *)filter->key.etype.etype.value = htons(proto);
802 *(__be16 *)filter->key.etype.etype.mask = htons(0xffff);
803 }
804 /* else, a filter of type OCELOT_VCAP_KEY_ANY is implicitly added */
805
806 return 0;
807}
808
809static int ocelot_flower_parse(struct ocelot *ocelot, int port, bool ingress,
810 struct flow_cls_offload *f,
811 struct ocelot_vcap_filter *filter)
812{
813 int ret;
814
815 filter->prio = f->common.prio;
816 filter->id.cookie = f->cookie;
817 filter->id.tc_offload = true;
818
819 ret = ocelot_flower_parse_action(ocelot, port, ingress, f, filter);
820 if (ret)
821 return ret;
822
823 /* PSFP filter need to parse key by stream identification function. */
824 if (filter->type == OCELOT_PSFP_FILTER_OFFLOAD)
825 return 0;
826
827 return ocelot_flower_parse_key(ocelot, port, ingress, f, filter);
828}
829
830static struct ocelot_vcap_filter
831*ocelot_vcap_filter_create(struct ocelot *ocelot, int port, bool ingress,
832 struct flow_cls_offload *f)
833{
834 struct ocelot_vcap_filter *filter;
835
836 filter = kzalloc(sizeof(*filter), GFP_KERNEL);
837 if (!filter)
838 return NULL;
839
840 if (ingress) {
841 filter->ingress_port_mask = BIT(port);
842 } else {
843 const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0];
844 int key_length = vcap->keys[VCAP_ES0_EGR_PORT].length;
845
846 filter->egress_port.value = port;
847 filter->egress_port.mask = GENMASK(key_length - 1, 0);
848 }
849
850 return filter;
851}
852
853static int ocelot_vcap_dummy_filter_add(struct ocelot *ocelot,
854 struct ocelot_vcap_filter *filter)
855{
856 list_add(&filter->list, &ocelot->dummy_rules);
857
858 return 0;
859}
860
861static int ocelot_vcap_dummy_filter_del(struct ocelot *ocelot,
862 struct ocelot_vcap_filter *filter)
863{
864 list_del(&filter->list);
865 kfree(filter);
866
867 return 0;
868}
869
870/* If we have an egress VLAN modification rule, we need to actually write the
871 * delta between the input VLAN (from the key) and the output VLAN (from the
872 * action), but the action was parsed first. So we need to patch the delta into
873 * the action here.
874 */
875static int
876ocelot_flower_patch_es0_vlan_modify(struct ocelot_vcap_filter *filter,
877 struct netlink_ext_ack *extack)
878{
879 if (filter->block_id != VCAP_ES0 ||
880 filter->action.tag_a_vid_sel != OCELOT_ES0_VID_PLUS_CLASSIFIED_VID)
881 return 0;
882
883 if (filter->vlan.vid.mask != VLAN_VID_MASK) {
884 NL_SET_ERR_MSG_MOD(extack,
885 "VCAP ES0 VLAN rewriting needs a full VLAN in the key");
886 return -EOPNOTSUPP;
887 }
888
889 filter->action.vid_a_val -= filter->vlan.vid.value;
890 filter->action.vid_a_val &= VLAN_VID_MASK;
891
892 return 0;
893}
894
895int ocelot_cls_flower_replace(struct ocelot *ocelot, int port,
896 struct flow_cls_offload *f, bool ingress)
897{
898 struct netlink_ext_ack *extack = f->common.extack;
899 struct ocelot_vcap_filter *filter;
900 int chain = f->common.chain_index;
901 int block_id, ret;
902
903 if (chain && !ocelot_find_vcap_filter_that_points_at(ocelot, chain)) {
904 NL_SET_ERR_MSG_MOD(extack, "No default GOTO action points to this chain");
905 return -EOPNOTSUPP;
906 }
907
908 block_id = ocelot_chain_to_block(chain, ingress);
909 if (block_id < 0) {
910 NL_SET_ERR_MSG_MOD(extack, "Cannot offload to this chain");
911 return -EOPNOTSUPP;
912 }
913
914 filter = ocelot_vcap_block_find_filter_by_id(&ocelot->block[block_id],
915 f->cookie, true);
916 if (filter) {
917 /* Filter already exists on other ports */
918 if (!ingress) {
919 NL_SET_ERR_MSG_MOD(extack, "VCAP ES0 does not support shared filters");
920 return -EOPNOTSUPP;
921 }
922
923 filter->ingress_port_mask |= BIT(port);
924
925 return ocelot_vcap_filter_replace(ocelot, filter);
926 }
927
928 /* Filter didn't exist, create it now */
929 filter = ocelot_vcap_filter_create(ocelot, port, ingress, f);
930 if (!filter)
931 return -ENOMEM;
932
933 ret = ocelot_flower_parse(ocelot, port, ingress, f, filter);
934 if (ret) {
935 kfree(filter);
936 return ret;
937 }
938
939 ret = ocelot_flower_patch_es0_vlan_modify(filter, extack);
940 if (ret) {
941 kfree(filter);
942 return ret;
943 }
944
945 /* The non-optional GOTOs for the TCAM skeleton don't need
946 * to be actually offloaded.
947 */
948 if (filter->type == OCELOT_VCAP_FILTER_DUMMY)
949 return ocelot_vcap_dummy_filter_add(ocelot, filter);
950
951 if (filter->type == OCELOT_PSFP_FILTER_OFFLOAD) {
952 kfree(filter);
953 if (ocelot->ops->psfp_filter_add)
954 return ocelot->ops->psfp_filter_add(ocelot, port, f);
955
956 NL_SET_ERR_MSG_MOD(extack, "PSFP chain is not supported in HW");
957 return -EOPNOTSUPP;
958 }
959
960 return ocelot_vcap_filter_add(ocelot, filter, f->common.extack);
961}
962EXPORT_SYMBOL_GPL(ocelot_cls_flower_replace);
963
964int ocelot_cls_flower_destroy(struct ocelot *ocelot, int port,
965 struct flow_cls_offload *f, bool ingress)
966{
967 struct ocelot_vcap_filter *filter;
968 struct ocelot_vcap_block *block;
969 int block_id;
970
971 block_id = ocelot_chain_to_block(f->common.chain_index, ingress);
972 if (block_id < 0)
973 return 0;
974
975 if (block_id == PSFP_BLOCK_ID) {
976 if (ocelot->ops->psfp_filter_del)
977 return ocelot->ops->psfp_filter_del(ocelot, f);
978
979 return -EOPNOTSUPP;
980 }
981
982 block = &ocelot->block[block_id];
983
984 filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true);
985 if (!filter)
986 return 0;
987
988 if (filter->type == OCELOT_VCAP_FILTER_DUMMY)
989 return ocelot_vcap_dummy_filter_del(ocelot, filter);
990
991 if (ingress) {
992 filter->ingress_port_mask &= ~BIT(port);
993 if (filter->ingress_port_mask)
994 return ocelot_vcap_filter_replace(ocelot, filter);
995 }
996
997 return ocelot_vcap_filter_del(ocelot, filter);
998}
999EXPORT_SYMBOL_GPL(ocelot_cls_flower_destroy);
1000
1001int ocelot_cls_flower_stats(struct ocelot *ocelot, int port,
1002 struct flow_cls_offload *f, bool ingress)
1003{
1004 struct ocelot_vcap_filter *filter;
1005 struct ocelot_vcap_block *block;
1006 struct flow_stats stats = {0};
1007 int block_id, ret;
1008
1009 block_id = ocelot_chain_to_block(f->common.chain_index, ingress);
1010 if (block_id < 0)
1011 return 0;
1012
1013 if (block_id == PSFP_BLOCK_ID) {
1014 if (ocelot->ops->psfp_stats_get) {
1015 ret = ocelot->ops->psfp_stats_get(ocelot, f, &stats);
1016 if (ret)
1017 return ret;
1018
1019 goto stats_update;
1020 }
1021
1022 return -EOPNOTSUPP;
1023 }
1024
1025 block = &ocelot->block[block_id];
1026
1027 filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true);
1028 if (!filter || filter->type == OCELOT_VCAP_FILTER_DUMMY)
1029 return 0;
1030
1031 ret = ocelot_vcap_filter_stats_update(ocelot, filter);
1032 if (ret)
1033 return ret;
1034
1035 stats.pkts = filter->stats.pkts;
1036
1037stats_update:
1038 flow_stats_update(&f->stats, 0x0, stats.pkts, stats.drops, 0x0,
1039 FLOW_ACTION_HW_STATS_IMMEDIATE);
1040 return 0;
1041}
1042EXPORT_SYMBOL_GPL(ocelot_cls_flower_stats);