GNU Linux-libre 6.8.7-gnu
[releases.git] / drivers / net / ethernet / mscc / ocelot_flower.c
1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
2 /* Microsemi Ocelot Switch driver
3  * Copyright (c) 2019 Microsemi Corporation
4  */
5
6 #include <net/pkt_cls.h>
7 #include <net/tc_act/tc_gact.h>
8 #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
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  */
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  */
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
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 *
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
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
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
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
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
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_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
613                 struct flow_match_control match;
614
615                 flow_rule_match_control(rule, &match);
616         }
617
618         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
619                 struct flow_match_vlan match;
620
621                 flow_rule_match_vlan(rule, &match);
622                 filter->key_type = OCELOT_VCAP_KEY_ANY;
623                 filter->vlan.vid.value = match.key->vlan_id;
624                 filter->vlan.vid.mask = match.mask->vlan_id;
625                 filter->vlan.pcp.value[0] = match.key->vlan_priority;
626                 filter->vlan.pcp.mask[0] = match.mask->vlan_priority;
627                 match_protocol = false;
628         }
629
630         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
631                 struct flow_match_eth_addrs match;
632
633                 if (filter->block_id == VCAP_ES0) {
634                         NL_SET_ERR_MSG_MOD(extack,
635                                            "VCAP ES0 cannot match on MAC address");
636                         return -EOPNOTSUPP;
637                 }
638
639                 /* The hw support mac matches only for MAC_ETYPE key,
640                  * therefore if other matches(port, tcp flags, etc) are added
641                  * then just bail out
642                  */
643                 if ((dissector->used_keys &
644                     (BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
645                      BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
646                      BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL))) !=
647                     (BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
648                      BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
649                      BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL)))
650                         return -EOPNOTSUPP;
651
652                 flow_rule_match_eth_addrs(rule, &match);
653
654                 if (filter->block_id == VCAP_IS1 &&
655                     !is_zero_ether_addr(match.mask->dst)) {
656                         NL_SET_ERR_MSG_MOD(extack,
657                                            "Key type S1_NORMAL cannot match on destination MAC");
658                         return -EOPNOTSUPP;
659                 }
660
661                 filter->key_type = OCELOT_VCAP_KEY_ETYPE;
662                 ether_addr_copy(filter->key.etype.dmac.value,
663                                 match.key->dst);
664                 ether_addr_copy(filter->key.etype.smac.value,
665                                 match.key->src);
666                 ether_addr_copy(filter->key.etype.dmac.mask,
667                                 match.mask->dst);
668                 ether_addr_copy(filter->key.etype.smac.mask,
669                                 match.mask->src);
670                 goto finished_key_parsing;
671         }
672
673         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
674                 struct flow_match_basic match;
675
676                 flow_rule_match_basic(rule, &match);
677                 if (ntohs(match.key->n_proto) == ETH_P_IP) {
678                         if (filter->block_id == VCAP_ES0) {
679                                 NL_SET_ERR_MSG_MOD(extack,
680                                                    "VCAP ES0 cannot match on IP protocol");
681                                 return -EOPNOTSUPP;
682                         }
683
684                         filter->key_type = OCELOT_VCAP_KEY_IPV4;
685                         filter->key.ipv4.proto.value[0] =
686                                 match.key->ip_proto;
687                         filter->key.ipv4.proto.mask[0] =
688                                 match.mask->ip_proto;
689                         match_protocol = false;
690                 }
691                 if (ntohs(match.key->n_proto) == ETH_P_IPV6) {
692                         if (filter->block_id == VCAP_ES0) {
693                                 NL_SET_ERR_MSG_MOD(extack,
694                                                    "VCAP ES0 cannot match on IP protocol");
695                                 return -EOPNOTSUPP;
696                         }
697
698                         filter->key_type = OCELOT_VCAP_KEY_IPV6;
699                         filter->key.ipv6.proto.value[0] =
700                                 match.key->ip_proto;
701                         filter->key.ipv6.proto.mask[0] =
702                                 match.mask->ip_proto;
703                         match_protocol = false;
704                 }
705         }
706
707         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS) &&
708             proto == ETH_P_IP) {
709                 struct flow_match_ipv4_addrs match;
710                 u8 *tmp;
711
712                 if (filter->block_id == VCAP_ES0) {
713                         NL_SET_ERR_MSG_MOD(extack,
714                                            "VCAP ES0 cannot match on IP address");
715                         return -EOPNOTSUPP;
716                 }
717
718                 flow_rule_match_ipv4_addrs(rule, &match);
719
720                 if (filter->block_id == VCAP_IS1 && *(u32 *)&match.mask->dst) {
721                         NL_SET_ERR_MSG_MOD(extack,
722                                            "Key type S1_NORMAL cannot match on destination IP");
723                         return -EOPNOTSUPP;
724                 }
725
726                 tmp = &filter->key.ipv4.sip.value.addr[0];
727                 memcpy(tmp, &match.key->src, 4);
728
729                 tmp = &filter->key.ipv4.sip.mask.addr[0];
730                 memcpy(tmp, &match.mask->src, 4);
731
732                 tmp = &filter->key.ipv4.dip.value.addr[0];
733                 memcpy(tmp, &match.key->dst, 4);
734
735                 tmp = &filter->key.ipv4.dip.mask.addr[0];
736                 memcpy(tmp, &match.mask->dst, 4);
737                 match_protocol = false;
738         }
739
740         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS) &&
741             proto == ETH_P_IPV6) {
742                 return -EOPNOTSUPP;
743         }
744
745         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
746                 struct flow_match_ports match;
747
748                 if (filter->block_id == VCAP_ES0) {
749                         NL_SET_ERR_MSG_MOD(extack,
750                                            "VCAP ES0 cannot match on L4 ports");
751                         return -EOPNOTSUPP;
752                 }
753
754                 flow_rule_match_ports(rule, &match);
755                 filter->key.ipv4.sport.value = ntohs(match.key->src);
756                 filter->key.ipv4.sport.mask = ntohs(match.mask->src);
757                 filter->key.ipv4.dport.value = ntohs(match.key->dst);
758                 filter->key.ipv4.dport.mask = ntohs(match.mask->dst);
759                 match_protocol = false;
760         }
761
762 finished_key_parsing:
763         if (match_protocol && proto != ETH_P_ALL) {
764                 if (filter->block_id == VCAP_ES0) {
765                         NL_SET_ERR_MSG_MOD(extack,
766                                            "VCAP ES0 cannot match on L2 proto");
767                         return -EOPNOTSUPP;
768                 }
769
770                 /* TODO: support SNAP, LLC etc */
771                 if (proto < ETH_P_802_3_MIN)
772                         return -EOPNOTSUPP;
773                 filter->key_type = OCELOT_VCAP_KEY_ETYPE;
774                 *(__be16 *)filter->key.etype.etype.value = htons(proto);
775                 *(__be16 *)filter->key.etype.etype.mask = htons(0xffff);
776         }
777         /* else, a filter of type OCELOT_VCAP_KEY_ANY is implicitly added */
778
779         return 0;
780 }
781
782 static int ocelot_flower_parse(struct ocelot *ocelot, int port, bool ingress,
783                                struct flow_cls_offload *f,
784                                struct ocelot_vcap_filter *filter)
785 {
786         int ret;
787
788         filter->prio = f->common.prio;
789         filter->id.cookie = f->cookie;
790         filter->id.tc_offload = true;
791
792         ret = ocelot_flower_parse_action(ocelot, port, ingress, f, filter);
793         if (ret)
794                 return ret;
795
796         /* PSFP filter need to parse key by stream identification function. */
797         if (filter->type == OCELOT_PSFP_FILTER_OFFLOAD)
798                 return 0;
799
800         return ocelot_flower_parse_key(ocelot, port, ingress, f, filter);
801 }
802
803 static struct ocelot_vcap_filter
804 *ocelot_vcap_filter_create(struct ocelot *ocelot, int port, bool ingress,
805                            struct flow_cls_offload *f)
806 {
807         struct ocelot_vcap_filter *filter;
808
809         filter = kzalloc(sizeof(*filter), GFP_KERNEL);
810         if (!filter)
811                 return NULL;
812
813         if (ingress) {
814                 filter->ingress_port_mask = BIT(port);
815         } else {
816                 const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0];
817                 int key_length = vcap->keys[VCAP_ES0_EGR_PORT].length;
818
819                 filter->egress_port.value = port;
820                 filter->egress_port.mask = GENMASK(key_length - 1, 0);
821         }
822
823         return filter;
824 }
825
826 static int ocelot_vcap_dummy_filter_add(struct ocelot *ocelot,
827                                         struct ocelot_vcap_filter *filter)
828 {
829         list_add(&filter->list, &ocelot->dummy_rules);
830
831         return 0;
832 }
833
834 static int ocelot_vcap_dummy_filter_del(struct ocelot *ocelot,
835                                         struct ocelot_vcap_filter *filter)
836 {
837         list_del(&filter->list);
838         kfree(filter);
839
840         return 0;
841 }
842
843 /* If we have an egress VLAN modification rule, we need to actually write the
844  * delta between the input VLAN (from the key) and the output VLAN (from the
845  * action), but the action was parsed first. So we need to patch the delta into
846  * the action here.
847  */
848 static int
849 ocelot_flower_patch_es0_vlan_modify(struct ocelot_vcap_filter *filter,
850                                     struct netlink_ext_ack *extack)
851 {
852         if (filter->block_id != VCAP_ES0 ||
853             filter->action.tag_a_vid_sel != OCELOT_ES0_VID_PLUS_CLASSIFIED_VID)
854                 return 0;
855
856         if (filter->vlan.vid.mask != VLAN_VID_MASK) {
857                 NL_SET_ERR_MSG_MOD(extack,
858                                    "VCAP ES0 VLAN rewriting needs a full VLAN in the key");
859                 return -EOPNOTSUPP;
860         }
861
862         filter->action.vid_a_val -= filter->vlan.vid.value;
863         filter->action.vid_a_val &= VLAN_VID_MASK;
864
865         return 0;
866 }
867
868 int ocelot_cls_flower_replace(struct ocelot *ocelot, int port,
869                               struct flow_cls_offload *f, bool ingress)
870 {
871         struct netlink_ext_ack *extack = f->common.extack;
872         struct ocelot_vcap_filter *filter;
873         int chain = f->common.chain_index;
874         int block_id, ret;
875
876         if (chain && !ocelot_find_vcap_filter_that_points_at(ocelot, chain)) {
877                 NL_SET_ERR_MSG_MOD(extack, "No default GOTO action points to this chain");
878                 return -EOPNOTSUPP;
879         }
880
881         block_id = ocelot_chain_to_block(chain, ingress);
882         if (block_id < 0) {
883                 NL_SET_ERR_MSG_MOD(extack, "Cannot offload to this chain");
884                 return -EOPNOTSUPP;
885         }
886
887         filter = ocelot_vcap_block_find_filter_by_id(&ocelot->block[block_id],
888                                                      f->cookie, true);
889         if (filter) {
890                 /* Filter already exists on other ports */
891                 if (!ingress) {
892                         NL_SET_ERR_MSG_MOD(extack, "VCAP ES0 does not support shared filters");
893                         return -EOPNOTSUPP;
894                 }
895
896                 filter->ingress_port_mask |= BIT(port);
897
898                 return ocelot_vcap_filter_replace(ocelot, filter);
899         }
900
901         /* Filter didn't exist, create it now */
902         filter = ocelot_vcap_filter_create(ocelot, port, ingress, f);
903         if (!filter)
904                 return -ENOMEM;
905
906         ret = ocelot_flower_parse(ocelot, port, ingress, f, filter);
907         if (ret) {
908                 kfree(filter);
909                 return ret;
910         }
911
912         ret = ocelot_flower_patch_es0_vlan_modify(filter, extack);
913         if (ret) {
914                 kfree(filter);
915                 return ret;
916         }
917
918         /* The non-optional GOTOs for the TCAM skeleton don't need
919          * to be actually offloaded.
920          */
921         if (filter->type == OCELOT_VCAP_FILTER_DUMMY)
922                 return ocelot_vcap_dummy_filter_add(ocelot, filter);
923
924         if (filter->type == OCELOT_PSFP_FILTER_OFFLOAD) {
925                 kfree(filter);
926                 if (ocelot->ops->psfp_filter_add)
927                         return ocelot->ops->psfp_filter_add(ocelot, port, f);
928
929                 NL_SET_ERR_MSG_MOD(extack, "PSFP chain is not supported in HW");
930                 return -EOPNOTSUPP;
931         }
932
933         return ocelot_vcap_filter_add(ocelot, filter, f->common.extack);
934 }
935 EXPORT_SYMBOL_GPL(ocelot_cls_flower_replace);
936
937 int ocelot_cls_flower_destroy(struct ocelot *ocelot, int port,
938                               struct flow_cls_offload *f, bool ingress)
939 {
940         struct ocelot_vcap_filter *filter;
941         struct ocelot_vcap_block *block;
942         int block_id;
943
944         block_id = ocelot_chain_to_block(f->common.chain_index, ingress);
945         if (block_id < 0)
946                 return 0;
947
948         if (block_id == PSFP_BLOCK_ID) {
949                 if (ocelot->ops->psfp_filter_del)
950                         return ocelot->ops->psfp_filter_del(ocelot, f);
951
952                 return -EOPNOTSUPP;
953         }
954
955         block = &ocelot->block[block_id];
956
957         filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true);
958         if (!filter)
959                 return 0;
960
961         if (filter->type == OCELOT_VCAP_FILTER_DUMMY)
962                 return ocelot_vcap_dummy_filter_del(ocelot, filter);
963
964         if (ingress) {
965                 filter->ingress_port_mask &= ~BIT(port);
966                 if (filter->ingress_port_mask)
967                         return ocelot_vcap_filter_replace(ocelot, filter);
968         }
969
970         return ocelot_vcap_filter_del(ocelot, filter);
971 }
972 EXPORT_SYMBOL_GPL(ocelot_cls_flower_destroy);
973
974 int ocelot_cls_flower_stats(struct ocelot *ocelot, int port,
975                             struct flow_cls_offload *f, bool ingress)
976 {
977         struct ocelot_vcap_filter *filter;
978         struct ocelot_vcap_block *block;
979         struct flow_stats stats = {0};
980         int block_id, ret;
981
982         block_id = ocelot_chain_to_block(f->common.chain_index, ingress);
983         if (block_id < 0)
984                 return 0;
985
986         if (block_id == PSFP_BLOCK_ID) {
987                 if (ocelot->ops->psfp_stats_get) {
988                         ret = ocelot->ops->psfp_stats_get(ocelot, f, &stats);
989                         if (ret)
990                                 return ret;
991
992                         goto stats_update;
993                 }
994
995                 return -EOPNOTSUPP;
996         }
997
998         block = &ocelot->block[block_id];
999
1000         filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true);
1001         if (!filter || filter->type == OCELOT_VCAP_FILTER_DUMMY)
1002                 return 0;
1003
1004         ret = ocelot_vcap_filter_stats_update(ocelot, filter);
1005         if (ret)
1006                 return ret;
1007
1008         stats.pkts = filter->stats.pkts;
1009
1010 stats_update:
1011         flow_stats_update(&f->stats, 0x0, stats.pkts, stats.drops, 0x0,
1012                           FLOW_ACTION_HW_STATS_IMMEDIATE);
1013         return 0;
1014 }
1015 EXPORT_SYMBOL_GPL(ocelot_cls_flower_stats);