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
ocelot_chain_to_block(int chain,bool ingress)28 static 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 */
ocelot_chain_to_lookup(int chain)62 static 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 */
ocelot_chain_to_pag(int chain)76 static 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
ocelot_is_goto_target_valid(int goto_target,int chain,bool ingress)92 static 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
144 static struct ocelot_vcap_filter *
ocelot_find_vcap_filter_that_points_at(struct ocelot * ocelot,int chain)145 ocelot_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
171 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)172 ocelot_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
200 static int
ocelot_flower_parse_egress_vlan_modify(struct ocelot_vcap_filter * filter,const struct flow_action_entry * a,struct netlink_ext_ack * extack)201 ocelot_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
ocelot_flower_parse_action(struct ocelot * ocelot,int port,bool ingress,struct flow_cls_offload * f,struct ocelot_vcap_filter * filter)231 static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
232 bool ingress, struct flow_cls_offload *f,
233 struct ocelot_vcap_filter *filter)
234 {
235 const struct flow_action *action = &f->rule->action;
236 struct netlink_ext_ack *extack = f->common.extack;
237 bool allow_missing_goto_target = false;
238 const struct flow_action_entry *a;
239 enum ocelot_tag_tpid_sel tpid;
240 int i, chain, egress_port;
241 u32 pol_ix, pol_max;
242 u64 rate;
243 int err;
244
245 if (!flow_action_basic_hw_stats_check(&f->rule->action,
246 f->common.extack))
247 return -EOPNOTSUPP;
248
249 chain = f->common.chain_index;
250 filter->block_id = ocelot_chain_to_block(chain, ingress);
251 if (filter->block_id < 0) {
252 NL_SET_ERR_MSG_MOD(extack, "Cannot offload to this chain");
253 return -EOPNOTSUPP;
254 }
255 if (filter->block_id == VCAP_IS1 || filter->block_id == VCAP_IS2)
256 filter->lookup = ocelot_chain_to_lookup(chain);
257 if (filter->block_id == VCAP_IS2)
258 filter->pag = ocelot_chain_to_pag(chain);
259
260 filter->goto_target = -1;
261 filter->type = OCELOT_VCAP_FILTER_DUMMY;
262
263 flow_action_for_each(i, a, action) {
264 switch (a->id) {
265 case FLOW_ACTION_DROP:
266 if (filter->block_id != VCAP_IS2) {
267 NL_SET_ERR_MSG_MOD(extack,
268 "Drop action can only be offloaded to VCAP IS2");
269 return -EOPNOTSUPP;
270 }
271 if (filter->goto_target != -1) {
272 NL_SET_ERR_MSG_MOD(extack,
273 "Last action must be GOTO");
274 return -EOPNOTSUPP;
275 }
276 filter->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY;
277 filter->action.port_mask = 0;
278 filter->action.police_ena = true;
279 filter->action.pol_ix = OCELOT_POLICER_DISCARD;
280 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
281 break;
282 case FLOW_ACTION_ACCEPT:
283 if (filter->block_id != VCAP_ES0 &&
284 filter->block_id != VCAP_IS1 &&
285 filter->block_id != VCAP_IS2) {
286 NL_SET_ERR_MSG_MOD(extack,
287 "Accept action can only be offloaded to VCAP chains");
288 return -EOPNOTSUPP;
289 }
290 if (filter->block_id != VCAP_ES0 &&
291 filter->goto_target != -1) {
292 NL_SET_ERR_MSG_MOD(extack,
293 "Last action must be GOTO");
294 return -EOPNOTSUPP;
295 }
296 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
297 break;
298 case FLOW_ACTION_TRAP:
299 if (filter->block_id != VCAP_IS2 ||
300 filter->lookup != 0) {
301 NL_SET_ERR_MSG_MOD(extack,
302 "Trap action can only be offloaded to VCAP IS2 lookup 0");
303 return -EOPNOTSUPP;
304 }
305 if (filter->goto_target != -1) {
306 NL_SET_ERR_MSG_MOD(extack,
307 "Last action must be GOTO");
308 return -EOPNOTSUPP;
309 }
310 filter->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY;
311 filter->action.port_mask = 0;
312 filter->action.cpu_copy_ena = true;
313 filter->action.cpu_qu_num = 0;
314 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
315 filter->is_trap = true;
316 break;
317 case FLOW_ACTION_POLICE:
318 if (filter->block_id == PSFP_BLOCK_ID) {
319 filter->type = OCELOT_PSFP_FILTER_OFFLOAD;
320 break;
321 }
322 if (filter->block_id != VCAP_IS2 ||
323 filter->lookup != 0) {
324 NL_SET_ERR_MSG_MOD(extack,
325 "Police action can only be offloaded to VCAP IS2 lookup 0 or PSFP");
326 return -EOPNOTSUPP;
327 }
328 if (filter->goto_target != -1) {
329 NL_SET_ERR_MSG_MOD(extack,
330 "Last action must be GOTO");
331 return -EOPNOTSUPP;
332 }
333
334 err = ocelot_policer_validate(action, a, extack);
335 if (err)
336 return err;
337
338 filter->action.police_ena = true;
339
340 pol_ix = a->hw_index + ocelot->vcap_pol.base;
341 pol_max = ocelot->vcap_pol.max;
342
343 if (ocelot->vcap_pol.max2 && pol_ix > pol_max) {
344 pol_ix += ocelot->vcap_pol.base2 - pol_max - 1;
345 pol_max = ocelot->vcap_pol.max2;
346 }
347
348 if (pol_ix >= pol_max)
349 return -EINVAL;
350
351 filter->action.pol_ix = pol_ix;
352
353 rate = a->police.rate_bytes_ps;
354 filter->action.pol.rate = div_u64(rate, 1000) * 8;
355 filter->action.pol.burst = a->police.burst;
356 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
357 break;
358 case FLOW_ACTION_REDIRECT:
359 if (filter->block_id != VCAP_IS2) {
360 NL_SET_ERR_MSG_MOD(extack,
361 "Redirect action can only be offloaded to VCAP IS2");
362 return -EOPNOTSUPP;
363 }
364 if (filter->goto_target != -1) {
365 NL_SET_ERR_MSG_MOD(extack,
366 "Last action must be GOTO");
367 return -EOPNOTSUPP;
368 }
369 egress_port = ocelot->ops->netdev_to_port(a->dev);
370 if (egress_port < 0) {
371 NL_SET_ERR_MSG_MOD(extack,
372 "Destination not an ocelot port");
373 return -EOPNOTSUPP;
374 }
375 filter->action.mask_mode = OCELOT_MASK_MODE_REDIRECT;
376 filter->action.port_mask = BIT(egress_port);
377 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
378 break;
379 case FLOW_ACTION_MIRRED:
380 if (filter->block_id != VCAP_IS2) {
381 NL_SET_ERR_MSG_MOD(extack,
382 "Mirror action can only be offloaded to VCAP IS2");
383 return -EOPNOTSUPP;
384 }
385 if (filter->goto_target != -1) {
386 NL_SET_ERR_MSG_MOD(extack,
387 "Last action must be GOTO");
388 return -EOPNOTSUPP;
389 }
390 egress_port = ocelot->ops->netdev_to_port(a->dev);
391 if (egress_port < 0) {
392 NL_SET_ERR_MSG_MOD(extack,
393 "Destination not an ocelot port");
394 return -EOPNOTSUPP;
395 }
396 filter->egress_port.value = egress_port;
397 filter->action.mirror_ena = true;
398 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
399 break;
400 case FLOW_ACTION_VLAN_POP:
401 if (filter->block_id != VCAP_IS1) {
402 NL_SET_ERR_MSG_MOD(extack,
403 "VLAN pop action can only be offloaded to VCAP IS1");
404 return -EOPNOTSUPP;
405 }
406 if (filter->goto_target != -1) {
407 NL_SET_ERR_MSG_MOD(extack,
408 "Last action must be GOTO");
409 return -EOPNOTSUPP;
410 }
411 filter->action.vlan_pop_cnt_ena = true;
412 filter->action.vlan_pop_cnt++;
413 if (filter->action.vlan_pop_cnt > 2) {
414 NL_SET_ERR_MSG_MOD(extack,
415 "Cannot pop more than 2 VLAN headers");
416 return -EOPNOTSUPP;
417 }
418 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
419 break;
420 case FLOW_ACTION_VLAN_MANGLE:
421 if (filter->block_id == VCAP_IS1) {
422 err = ocelot_flower_parse_ingress_vlan_modify(ocelot, port,
423 filter, a,
424 extack);
425 } else if (filter->block_id == VCAP_ES0) {
426 err = ocelot_flower_parse_egress_vlan_modify(filter, a,
427 extack);
428 } else {
429 NL_SET_ERR_MSG_MOD(extack,
430 "VLAN modify action can only be offloaded to VCAP IS1 or ES0");
431 err = -EOPNOTSUPP;
432 }
433 if (err)
434 return err;
435 break;
436 case FLOW_ACTION_PRIORITY:
437 if (filter->block_id != VCAP_IS1) {
438 NL_SET_ERR_MSG_MOD(extack,
439 "Priority action can only be offloaded to VCAP IS1");
440 return -EOPNOTSUPP;
441 }
442 if (filter->goto_target != -1) {
443 NL_SET_ERR_MSG_MOD(extack,
444 "Last action must be GOTO");
445 return -EOPNOTSUPP;
446 }
447 filter->action.qos_ena = true;
448 filter->action.qos_val = a->priority;
449 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
450 break;
451 case FLOW_ACTION_GOTO:
452 filter->goto_target = a->chain_index;
453
454 if (filter->block_id == VCAP_IS1 && filter->lookup == 2) {
455 int pag = ocelot_chain_to_pag(filter->goto_target);
456
457 filter->action.pag_override_mask = 0xff;
458 filter->action.pag_val = pag;
459 filter->type = OCELOT_VCAP_FILTER_PAG;
460 }
461 break;
462 case FLOW_ACTION_VLAN_PUSH:
463 if (filter->block_id != VCAP_ES0) {
464 NL_SET_ERR_MSG_MOD(extack,
465 "VLAN push action can only be offloaded to VCAP ES0");
466 return -EOPNOTSUPP;
467 }
468 switch (ntohs(a->vlan.proto)) {
469 case ETH_P_8021Q:
470 tpid = OCELOT_TAG_TPID_SEL_8021Q;
471 break;
472 case ETH_P_8021AD:
473 tpid = OCELOT_TAG_TPID_SEL_8021AD;
474 break;
475 default:
476 NL_SET_ERR_MSG_MOD(extack,
477 "Cannot push custom TPID");
478 return -EOPNOTSUPP;
479 }
480 filter->action.tag_a_tpid_sel = tpid;
481 filter->action.push_outer_tag = OCELOT_ES0_TAG;
482 filter->action.tag_a_vid_sel = OCELOT_ES0_VID;
483 filter->action.vid_a_val = a->vlan.vid;
484 filter->action.pcp_a_val = a->vlan.prio;
485 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
486 break;
487 case FLOW_ACTION_GATE:
488 if (filter->block_id != PSFP_BLOCK_ID) {
489 NL_SET_ERR_MSG_MOD(extack,
490 "Gate action can only be offloaded to PSFP chain");
491 return -EOPNOTSUPP;
492 }
493 filter->type = OCELOT_PSFP_FILTER_OFFLOAD;
494 break;
495 default:
496 NL_SET_ERR_MSG_MOD(extack, "Cannot offload action");
497 return -EOPNOTSUPP;
498 }
499 }
500
501 if (filter->goto_target == -1) {
502 if ((filter->block_id == VCAP_IS2 && filter->lookup == 1) ||
503 chain == 0 || filter->block_id == PSFP_BLOCK_ID) {
504 allow_missing_goto_target = true;
505 } else {
506 NL_SET_ERR_MSG_MOD(extack, "Missing GOTO action");
507 return -EOPNOTSUPP;
508 }
509 }
510
511 if (!ocelot_is_goto_target_valid(filter->goto_target, chain, ingress) &&
512 !allow_missing_goto_target) {
513 NL_SET_ERR_MSG_MOD(extack, "Cannot offload this GOTO target");
514 return -EOPNOTSUPP;
515 }
516
517 return 0;
518 }
519
ocelot_flower_parse_indev(struct ocelot * ocelot,int port,struct flow_cls_offload * f,struct ocelot_vcap_filter * filter)520 static int ocelot_flower_parse_indev(struct ocelot *ocelot, int port,
521 struct flow_cls_offload *f,
522 struct ocelot_vcap_filter *filter)
523 {
524 struct flow_rule *rule = flow_cls_offload_flow_rule(f);
525 const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0];
526 int key_length = vcap->keys[VCAP_ES0_IGR_PORT].length;
527 struct netlink_ext_ack *extack = f->common.extack;
528 struct net_device *dev, *indev;
529 struct flow_match_meta match;
530 int ingress_port;
531
532 flow_rule_match_meta(rule, &match);
533
534 if (!match.mask->ingress_ifindex)
535 return 0;
536
537 if (match.mask->ingress_ifindex != 0xFFFFFFFF) {
538 NL_SET_ERR_MSG_MOD(extack, "Unsupported ingress ifindex mask");
539 return -EOPNOTSUPP;
540 }
541
542 dev = ocelot->ops->port_to_netdev(ocelot, port);
543 if (!dev)
544 return -EINVAL;
545
546 indev = __dev_get_by_index(dev_net(dev), match.key->ingress_ifindex);
547 if (!indev) {
548 NL_SET_ERR_MSG_MOD(extack,
549 "Can't find the ingress port to match on");
550 return -ENOENT;
551 }
552
553 ingress_port = ocelot->ops->netdev_to_port(indev);
554 if (ingress_port < 0) {
555 NL_SET_ERR_MSG_MOD(extack,
556 "Can only offload an ocelot ingress port");
557 return -EOPNOTSUPP;
558 }
559 if (ingress_port == port) {
560 NL_SET_ERR_MSG_MOD(extack,
561 "Ingress port is equal to the egress port");
562 return -EINVAL;
563 }
564
565 filter->ingress_port.value = ingress_port;
566 filter->ingress_port.mask = GENMASK(key_length - 1, 0);
567
568 return 0;
569 }
570
571 static int
ocelot_flower_parse_key(struct ocelot * ocelot,int port,bool ingress,struct flow_cls_offload * f,struct ocelot_vcap_filter * filter)572 ocelot_flower_parse_key(struct ocelot *ocelot, int port, bool ingress,
573 struct flow_cls_offload *f,
574 struct ocelot_vcap_filter *filter)
575 {
576 struct flow_rule *rule = flow_cls_offload_flow_rule(f);
577 struct flow_dissector *dissector = rule->match.dissector;
578 struct netlink_ext_ack *extack = f->common.extack;
579 u16 proto = ntohs(f->common.protocol);
580 bool match_protocol = true;
581 int ret;
582
583 if (dissector->used_keys &
584 ~(BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) |
585 BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
586 BIT_ULL(FLOW_DISSECTOR_KEY_META) |
587 BIT_ULL(FLOW_DISSECTOR_KEY_PORTS) |
588 BIT_ULL(FLOW_DISSECTOR_KEY_VLAN) |
589 BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
590 BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
591 BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
592 return -EOPNOTSUPP;
593 }
594
595 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_META)) {
596 struct flow_match_meta match;
597
598 flow_rule_match_meta(rule, &match);
599 if (match.mask->l2_miss) {
600 NL_SET_ERR_MSG_MOD(extack, "Can't match on \"l2_miss\"");
601 return -EOPNOTSUPP;
602 }
603 }
604
605 /* For VCAP ES0 (egress rewriter) we can match on the ingress port */
606 if (!ingress) {
607 ret = ocelot_flower_parse_indev(ocelot, port, f, filter);
608 if (ret)
609 return ret;
610 }
611
612 if (flow_rule_match_has_control_flags(rule, extack))
613 return -EOPNOTSUPP;
614
615 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
616 struct flow_match_vlan match;
617
618 flow_rule_match_vlan(rule, &match);
619 filter->key_type = OCELOT_VCAP_KEY_ANY;
620 filter->vlan.vid.value = match.key->vlan_id;
621 filter->vlan.vid.mask = match.mask->vlan_id;
622 filter->vlan.pcp.value[0] = match.key->vlan_priority;
623 filter->vlan.pcp.mask[0] = match.mask->vlan_priority;
624 match_protocol = false;
625 }
626
627 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
628 struct flow_match_eth_addrs match;
629
630 if (filter->block_id == VCAP_ES0) {
631 NL_SET_ERR_MSG_MOD(extack,
632 "VCAP ES0 cannot match on MAC address");
633 return -EOPNOTSUPP;
634 }
635
636 /* The hw support mac matches only for MAC_ETYPE key,
637 * therefore if other matches(port, tcp flags, etc) are added
638 * then just bail out
639 */
640 if ((dissector->used_keys &
641 (BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
642 BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
643 BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL))) !=
644 (BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
645 BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
646 BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL)))
647 return -EOPNOTSUPP;
648
649 flow_rule_match_eth_addrs(rule, &match);
650
651 if (filter->block_id == VCAP_IS1 &&
652 !is_zero_ether_addr(match.mask->dst)) {
653 NL_SET_ERR_MSG_MOD(extack,
654 "Key type S1_NORMAL cannot match on destination MAC");
655 return -EOPNOTSUPP;
656 }
657
658 filter->key_type = OCELOT_VCAP_KEY_ETYPE;
659 ether_addr_copy(filter->key.etype.dmac.value,
660 match.key->dst);
661 ether_addr_copy(filter->key.etype.smac.value,
662 match.key->src);
663 ether_addr_copy(filter->key.etype.dmac.mask,
664 match.mask->dst);
665 ether_addr_copy(filter->key.etype.smac.mask,
666 match.mask->src);
667 goto finished_key_parsing;
668 }
669
670 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
671 struct flow_match_basic match;
672
673 flow_rule_match_basic(rule, &match);
674 if (ntohs(match.key->n_proto) == ETH_P_IP) {
675 if (filter->block_id == VCAP_ES0) {
676 NL_SET_ERR_MSG_MOD(extack,
677 "VCAP ES0 cannot match on IP protocol");
678 return -EOPNOTSUPP;
679 }
680
681 filter->key_type = OCELOT_VCAP_KEY_IPV4;
682 filter->key.ipv4.proto.value[0] =
683 match.key->ip_proto;
684 filter->key.ipv4.proto.mask[0] =
685 match.mask->ip_proto;
686 match_protocol = false;
687 }
688 if (ntohs(match.key->n_proto) == ETH_P_IPV6) {
689 if (filter->block_id == VCAP_ES0) {
690 NL_SET_ERR_MSG_MOD(extack,
691 "VCAP ES0 cannot match on IP protocol");
692 return -EOPNOTSUPP;
693 }
694
695 filter->key_type = OCELOT_VCAP_KEY_IPV6;
696 filter->key.ipv6.proto.value[0] =
697 match.key->ip_proto;
698 filter->key.ipv6.proto.mask[0] =
699 match.mask->ip_proto;
700 match_protocol = false;
701 }
702 }
703
704 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS) &&
705 proto == ETH_P_IP) {
706 struct flow_match_ipv4_addrs match;
707 u8 *tmp;
708
709 if (filter->block_id == VCAP_ES0) {
710 NL_SET_ERR_MSG_MOD(extack,
711 "VCAP ES0 cannot match on IP address");
712 return -EOPNOTSUPP;
713 }
714
715 flow_rule_match_ipv4_addrs(rule, &match);
716
717 if (filter->block_id == VCAP_IS1 && *(u32 *)&match.mask->dst) {
718 NL_SET_ERR_MSG_MOD(extack,
719 "Key type S1_NORMAL cannot match on destination IP");
720 return -EOPNOTSUPP;
721 }
722
723 tmp = &filter->key.ipv4.sip.value.addr[0];
724 memcpy(tmp, &match.key->src, 4);
725
726 tmp = &filter->key.ipv4.sip.mask.addr[0];
727 memcpy(tmp, &match.mask->src, 4);
728
729 tmp = &filter->key.ipv4.dip.value.addr[0];
730 memcpy(tmp, &match.key->dst, 4);
731
732 tmp = &filter->key.ipv4.dip.mask.addr[0];
733 memcpy(tmp, &match.mask->dst, 4);
734 match_protocol = false;
735 }
736
737 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS) &&
738 proto == ETH_P_IPV6) {
739 return -EOPNOTSUPP;
740 }
741
742 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
743 struct flow_match_ports match;
744
745 if (filter->block_id == VCAP_ES0) {
746 NL_SET_ERR_MSG_MOD(extack,
747 "VCAP ES0 cannot match on L4 ports");
748 return -EOPNOTSUPP;
749 }
750
751 flow_rule_match_ports(rule, &match);
752 filter->key.ipv4.sport.value = ntohs(match.key->src);
753 filter->key.ipv4.sport.mask = ntohs(match.mask->src);
754 filter->key.ipv4.dport.value = ntohs(match.key->dst);
755 filter->key.ipv4.dport.mask = ntohs(match.mask->dst);
756 match_protocol = false;
757 }
758
759 finished_key_parsing:
760 if (match_protocol && proto != ETH_P_ALL) {
761 if (filter->block_id == VCAP_ES0) {
762 NL_SET_ERR_MSG_MOD(extack,
763 "VCAP ES0 cannot match on L2 proto");
764 return -EOPNOTSUPP;
765 }
766
767 /* TODO: support SNAP, LLC etc */
768 if (proto < ETH_P_802_3_MIN)
769 return -EOPNOTSUPP;
770 filter->key_type = OCELOT_VCAP_KEY_ETYPE;
771 *(__be16 *)filter->key.etype.etype.value = htons(proto);
772 *(__be16 *)filter->key.etype.etype.mask = htons(0xffff);
773 }
774 /* else, a filter of type OCELOT_VCAP_KEY_ANY is implicitly added */
775
776 return 0;
777 }
778
ocelot_flower_parse(struct ocelot * ocelot,int port,bool ingress,struct flow_cls_offload * f,struct ocelot_vcap_filter * filter)779 static int ocelot_flower_parse(struct ocelot *ocelot, int port, bool ingress,
780 struct flow_cls_offload *f,
781 struct ocelot_vcap_filter *filter)
782 {
783 int ret;
784
785 filter->prio = f->common.prio;
786 filter->id.cookie = f->cookie;
787 filter->id.tc_offload = true;
788
789 ret = ocelot_flower_parse_action(ocelot, port, ingress, f, filter);
790 if (ret)
791 return ret;
792
793 /* PSFP filter need to parse key by stream identification function. */
794 if (filter->type == OCELOT_PSFP_FILTER_OFFLOAD)
795 return 0;
796
797 return ocelot_flower_parse_key(ocelot, port, ingress, f, filter);
798 }
799
800 static struct ocelot_vcap_filter
ocelot_vcap_filter_create(struct ocelot * ocelot,int port,bool ingress,struct flow_cls_offload * f)801 *ocelot_vcap_filter_create(struct ocelot *ocelot, int port, bool ingress,
802 struct flow_cls_offload *f)
803 {
804 struct ocelot_vcap_filter *filter;
805
806 filter = kzalloc(sizeof(*filter), GFP_KERNEL);
807 if (!filter)
808 return NULL;
809
810 if (ingress) {
811 filter->ingress_port_mask = BIT(port);
812 } else {
813 const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0];
814 int key_length = vcap->keys[VCAP_ES0_EGR_PORT].length;
815
816 filter->egress_port.value = port;
817 filter->egress_port.mask = GENMASK(key_length - 1, 0);
818 }
819
820 return filter;
821 }
822
ocelot_vcap_dummy_filter_add(struct ocelot * ocelot,struct ocelot_vcap_filter * filter)823 static int ocelot_vcap_dummy_filter_add(struct ocelot *ocelot,
824 struct ocelot_vcap_filter *filter)
825 {
826 list_add(&filter->list, &ocelot->dummy_rules);
827
828 return 0;
829 }
830
ocelot_vcap_dummy_filter_del(struct ocelot * ocelot,struct ocelot_vcap_filter * filter)831 static int ocelot_vcap_dummy_filter_del(struct ocelot *ocelot,
832 struct ocelot_vcap_filter *filter)
833 {
834 list_del(&filter->list);
835 kfree(filter);
836
837 return 0;
838 }
839
840 /* If we have an egress VLAN modification rule, we need to actually write the
841 * delta between the input VLAN (from the key) and the output VLAN (from the
842 * action), but the action was parsed first. So we need to patch the delta into
843 * the action here.
844 */
845 static int
ocelot_flower_patch_es0_vlan_modify(struct ocelot_vcap_filter * filter,struct netlink_ext_ack * extack)846 ocelot_flower_patch_es0_vlan_modify(struct ocelot_vcap_filter *filter,
847 struct netlink_ext_ack *extack)
848 {
849 if (filter->block_id != VCAP_ES0 ||
850 filter->action.tag_a_vid_sel != OCELOT_ES0_VID_PLUS_CLASSIFIED_VID)
851 return 0;
852
853 if (filter->vlan.vid.mask != VLAN_VID_MASK) {
854 NL_SET_ERR_MSG_MOD(extack,
855 "VCAP ES0 VLAN rewriting needs a full VLAN in the key");
856 return -EOPNOTSUPP;
857 }
858
859 filter->action.vid_a_val -= filter->vlan.vid.value;
860 filter->action.vid_a_val &= VLAN_VID_MASK;
861
862 return 0;
863 }
864
ocelot_cls_flower_replace(struct ocelot * ocelot,int port,struct flow_cls_offload * f,bool ingress)865 int ocelot_cls_flower_replace(struct ocelot *ocelot, int port,
866 struct flow_cls_offload *f, bool ingress)
867 {
868 struct netlink_ext_ack *extack = f->common.extack;
869 struct ocelot_vcap_filter *filter;
870 int chain = f->common.chain_index;
871 int block_id, ret;
872
873 if (chain && !ocelot_find_vcap_filter_that_points_at(ocelot, chain)) {
874 NL_SET_ERR_MSG_MOD(extack, "No default GOTO action points to this chain");
875 return -EOPNOTSUPP;
876 }
877
878 block_id = ocelot_chain_to_block(chain, ingress);
879 if (block_id < 0) {
880 NL_SET_ERR_MSG_MOD(extack, "Cannot offload to this chain");
881 return -EOPNOTSUPP;
882 }
883
884 filter = ocelot_vcap_block_find_filter_by_id(&ocelot->block[block_id],
885 f->cookie, true);
886 if (filter) {
887 /* Filter already exists on other ports */
888 if (!ingress) {
889 NL_SET_ERR_MSG_MOD(extack, "VCAP ES0 does not support shared filters");
890 return -EOPNOTSUPP;
891 }
892
893 filter->ingress_port_mask |= BIT(port);
894
895 return ocelot_vcap_filter_replace(ocelot, filter);
896 }
897
898 /* Filter didn't exist, create it now */
899 filter = ocelot_vcap_filter_create(ocelot, port, ingress, f);
900 if (!filter)
901 return -ENOMEM;
902
903 ret = ocelot_flower_parse(ocelot, port, ingress, f, filter);
904 if (ret) {
905 kfree(filter);
906 return ret;
907 }
908
909 ret = ocelot_flower_patch_es0_vlan_modify(filter, extack);
910 if (ret) {
911 kfree(filter);
912 return ret;
913 }
914
915 /* The non-optional GOTOs for the TCAM skeleton don't need
916 * to be actually offloaded.
917 */
918 if (filter->type == OCELOT_VCAP_FILTER_DUMMY)
919 return ocelot_vcap_dummy_filter_add(ocelot, filter);
920
921 if (filter->type == OCELOT_PSFP_FILTER_OFFLOAD) {
922 kfree(filter);
923 if (ocelot->ops->psfp_filter_add)
924 return ocelot->ops->psfp_filter_add(ocelot, port, f);
925
926 NL_SET_ERR_MSG_MOD(extack, "PSFP chain is not supported in HW");
927 return -EOPNOTSUPP;
928 }
929
930 return ocelot_vcap_filter_add(ocelot, filter, f->common.extack);
931 }
932 EXPORT_SYMBOL_GPL(ocelot_cls_flower_replace);
933
ocelot_cls_flower_destroy(struct ocelot * ocelot,int port,struct flow_cls_offload * f,bool ingress)934 int ocelot_cls_flower_destroy(struct ocelot *ocelot, int port,
935 struct flow_cls_offload *f, bool ingress)
936 {
937 struct ocelot_vcap_filter *filter;
938 struct ocelot_vcap_block *block;
939 int block_id;
940
941 block_id = ocelot_chain_to_block(f->common.chain_index, ingress);
942 if (block_id < 0)
943 return 0;
944
945 if (block_id == PSFP_BLOCK_ID) {
946 if (ocelot->ops->psfp_filter_del)
947 return ocelot->ops->psfp_filter_del(ocelot, f);
948
949 return -EOPNOTSUPP;
950 }
951
952 block = &ocelot->block[block_id];
953
954 filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true);
955 if (!filter)
956 return 0;
957
958 if (filter->type == OCELOT_VCAP_FILTER_DUMMY)
959 return ocelot_vcap_dummy_filter_del(ocelot, filter);
960
961 if (ingress) {
962 filter->ingress_port_mask &= ~BIT(port);
963 if (filter->ingress_port_mask)
964 return ocelot_vcap_filter_replace(ocelot, filter);
965 }
966
967 return ocelot_vcap_filter_del(ocelot, filter);
968 }
969 EXPORT_SYMBOL_GPL(ocelot_cls_flower_destroy);
970
ocelot_cls_flower_stats(struct ocelot * ocelot,int port,struct flow_cls_offload * f,bool ingress)971 int ocelot_cls_flower_stats(struct ocelot *ocelot, int port,
972 struct flow_cls_offload *f, bool ingress)
973 {
974 struct ocelot_vcap_filter *filter;
975 struct ocelot_vcap_block *block;
976 struct flow_stats stats = {0};
977 int block_id, ret;
978
979 block_id = ocelot_chain_to_block(f->common.chain_index, ingress);
980 if (block_id < 0)
981 return 0;
982
983 if (block_id == PSFP_BLOCK_ID) {
984 if (ocelot->ops->psfp_stats_get) {
985 ret = ocelot->ops->psfp_stats_get(ocelot, f, &stats);
986 if (ret)
987 return ret;
988
989 goto stats_update;
990 }
991
992 return -EOPNOTSUPP;
993 }
994
995 block = &ocelot->block[block_id];
996
997 filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true);
998 if (!filter || filter->type == OCELOT_VCAP_FILTER_DUMMY)
999 return 0;
1000
1001 ret = ocelot_vcap_filter_stats_update(ocelot, filter);
1002 if (ret)
1003 return ret;
1004
1005 stats.pkts = filter->stats.pkts;
1006
1007 stats_update:
1008 flow_stats_update(&f->stats, 0x0, stats.pkts, stats.drops, 0x0,
1009 FLOW_ACTION_HW_STATS_IMMEDIATE);
1010 return 0;
1011 }
1012 EXPORT_SYMBOL_GPL(ocelot_cls_flower_stats);
1013