Loading...
1// SPDX-License-Identifier: GPL-2.0+
2/* Microchip VCAP API
3 *
4 * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.
5 */
6
7#include <net/tc_act/tc_gate.h>
8#include <net/tcp.h>
9
10#include "sparx5_tc.h"
11#include "vcap_api.h"
12#include "vcap_api_client.h"
13#include "vcap_tc.h"
14#include "sparx5_main.h"
15#include "sparx5_vcap_impl.h"
16
17#define SPX5_MAX_RULE_SIZE 13 /* allows X1, X2, X4, X6 and X12 rules */
18
19/* Collect keysets and type ids for multiple rules per size */
20struct sparx5_wildcard_rule {
21 bool selected;
22 u8 value;
23 u8 mask;
24 enum vcap_keyfield_set keyset;
25};
26
27struct sparx5_multiple_rules {
28 struct sparx5_wildcard_rule rule[SPX5_MAX_RULE_SIZE];
29};
30
31struct sparx5_tc_flower_template {
32 struct list_head list; /* for insertion in the list of templates */
33 int cid; /* chain id */
34 enum vcap_keyfield_set orig; /* keyset used before the template */
35 enum vcap_keyfield_set keyset; /* new keyset used by template */
36 u16 l3_proto; /* protocol specified in the template */
37};
38
39static int
40sparx5_tc_flower_es0_tpid(struct vcap_tc_flower_parse_usage *st)
41{
42 int err = 0;
43
44 switch (st->tpid) {
45 case ETH_P_8021Q:
46 err = vcap_rule_add_key_u32(st->vrule,
47 VCAP_KF_8021Q_TPID,
48 SPX5_TPID_SEL_8100, ~0);
49 break;
50 case ETH_P_8021AD:
51 err = vcap_rule_add_key_u32(st->vrule,
52 VCAP_KF_8021Q_TPID,
53 SPX5_TPID_SEL_88A8, ~0);
54 break;
55 default:
56 NL_SET_ERR_MSG_MOD(st->fco->common.extack,
57 "Invalid vlan proto");
58 err = -EINVAL;
59 break;
60 }
61 return err;
62}
63
64static int
65sparx5_tc_flower_handler_basic_usage(struct vcap_tc_flower_parse_usage *st)
66{
67 struct flow_match_basic mt;
68 int err = 0;
69
70 flow_rule_match_basic(st->frule, &mt);
71
72 if (mt.mask->n_proto) {
73 st->l3_proto = be16_to_cpu(mt.key->n_proto);
74 if (!sparx5_vcap_is_known_etype(st->admin, st->l3_proto)) {
75 err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_ETYPE,
76 st->l3_proto, ~0);
77 if (err)
78 goto out;
79 } else if (st->l3_proto == ETH_P_IP) {
80 err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS,
81 VCAP_BIT_1);
82 if (err)
83 goto out;
84 } else if (st->l3_proto == ETH_P_IPV6) {
85 err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS,
86 VCAP_BIT_0);
87 if (err)
88 goto out;
89 if (st->admin->vtype == VCAP_TYPE_IS0) {
90 err = vcap_rule_add_key_bit(st->vrule,
91 VCAP_KF_IP_SNAP_IS,
92 VCAP_BIT_1);
93 if (err)
94 goto out;
95 }
96 }
97 }
98
99 if (mt.mask->ip_proto) {
100 st->l4_proto = mt.key->ip_proto;
101 if (st->l4_proto == IPPROTO_TCP) {
102 err = vcap_rule_add_key_bit(st->vrule,
103 VCAP_KF_TCP_IS,
104 VCAP_BIT_1);
105 if (err)
106 goto out;
107 } else if (st->l4_proto == IPPROTO_UDP) {
108 err = vcap_rule_add_key_bit(st->vrule,
109 VCAP_KF_TCP_IS,
110 VCAP_BIT_0);
111 if (err)
112 goto out;
113 if (st->admin->vtype == VCAP_TYPE_IS0) {
114 err = vcap_rule_add_key_bit(st->vrule,
115 VCAP_KF_TCP_UDP_IS,
116 VCAP_BIT_1);
117 if (err)
118 goto out;
119 }
120 } else {
121 err = vcap_rule_add_key_u32(st->vrule,
122 VCAP_KF_L3_IP_PROTO,
123 st->l4_proto, ~0);
124 if (err)
125 goto out;
126 }
127 }
128
129 st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_BASIC);
130
131 return err;
132
133out:
134 NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_proto parse error");
135 return err;
136}
137
138static int
139sparx5_tc_flower_handler_control_usage(struct vcap_tc_flower_parse_usage *st)
140{
141 struct flow_match_control mt;
142 u32 value, mask;
143 int err = 0;
144
145 flow_rule_match_control(st->frule, &mt);
146
147 if (mt.mask->flags) {
148 if (mt.mask->flags & FLOW_DIS_FIRST_FRAG) {
149 if (mt.key->flags & FLOW_DIS_FIRST_FRAG) {
150 value = 1; /* initial fragment */
151 mask = 0x3;
152 } else {
153 if (mt.mask->flags & FLOW_DIS_IS_FRAGMENT) {
154 value = 3; /* follow up fragment */
155 mask = 0x3;
156 } else {
157 value = 0; /* no fragment */
158 mask = 0x3;
159 }
160 }
161 } else {
162 if (mt.mask->flags & FLOW_DIS_IS_FRAGMENT) {
163 value = 3; /* follow up fragment */
164 mask = 0x3;
165 } else {
166 value = 0; /* no fragment */
167 mask = 0x3;
168 }
169 }
170
171 err = vcap_rule_add_key_u32(st->vrule,
172 VCAP_KF_L3_FRAGMENT_TYPE,
173 value, mask);
174 if (err)
175 goto out;
176 }
177
178 st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL);
179
180 return err;
181
182out:
183 NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_frag parse error");
184 return err;
185}
186
187static int
188sparx5_tc_flower_handler_cvlan_usage(struct vcap_tc_flower_parse_usage *st)
189{
190 if (st->admin->vtype != VCAP_TYPE_IS0) {
191 NL_SET_ERR_MSG_MOD(st->fco->common.extack,
192 "cvlan not supported in this VCAP");
193 return -EINVAL;
194 }
195
196 return vcap_tc_flower_handler_cvlan_usage(st);
197}
198
199static int
200sparx5_tc_flower_handler_vlan_usage(struct vcap_tc_flower_parse_usage *st)
201{
202 enum vcap_key_field vid_key = VCAP_KF_8021Q_VID_CLS;
203 enum vcap_key_field pcp_key = VCAP_KF_8021Q_PCP_CLS;
204 int err;
205
206 if (st->admin->vtype == VCAP_TYPE_IS0) {
207 vid_key = VCAP_KF_8021Q_VID0;
208 pcp_key = VCAP_KF_8021Q_PCP0;
209 }
210
211 err = vcap_tc_flower_handler_vlan_usage(st, vid_key, pcp_key);
212 if (err)
213 return err;
214
215 if (st->admin->vtype == VCAP_TYPE_ES0 && st->tpid)
216 err = sparx5_tc_flower_es0_tpid(st);
217
218 return err;
219}
220
221static int (*sparx5_tc_flower_usage_handlers[])(struct vcap_tc_flower_parse_usage *st) = {
222 [FLOW_DISSECTOR_KEY_ETH_ADDRS] = vcap_tc_flower_handler_ethaddr_usage,
223 [FLOW_DISSECTOR_KEY_IPV4_ADDRS] = vcap_tc_flower_handler_ipv4_usage,
224 [FLOW_DISSECTOR_KEY_IPV6_ADDRS] = vcap_tc_flower_handler_ipv6_usage,
225 [FLOW_DISSECTOR_KEY_CONTROL] = sparx5_tc_flower_handler_control_usage,
226 [FLOW_DISSECTOR_KEY_PORTS] = vcap_tc_flower_handler_portnum_usage,
227 [FLOW_DISSECTOR_KEY_BASIC] = sparx5_tc_flower_handler_basic_usage,
228 [FLOW_DISSECTOR_KEY_CVLAN] = sparx5_tc_flower_handler_cvlan_usage,
229 [FLOW_DISSECTOR_KEY_VLAN] = sparx5_tc_flower_handler_vlan_usage,
230 [FLOW_DISSECTOR_KEY_TCP] = vcap_tc_flower_handler_tcp_usage,
231 [FLOW_DISSECTOR_KEY_ARP] = vcap_tc_flower_handler_arp_usage,
232 [FLOW_DISSECTOR_KEY_IP] = vcap_tc_flower_handler_ip_usage,
233};
234
235static int sparx5_tc_use_dissectors(struct vcap_tc_flower_parse_usage *st,
236 struct vcap_admin *admin,
237 struct vcap_rule *vrule)
238{
239 int idx, err = 0;
240
241 for (idx = 0; idx < ARRAY_SIZE(sparx5_tc_flower_usage_handlers); ++idx) {
242 if (!flow_rule_match_key(st->frule, idx))
243 continue;
244 if (!sparx5_tc_flower_usage_handlers[idx])
245 continue;
246 err = sparx5_tc_flower_usage_handlers[idx](st);
247 if (err)
248 return err;
249 }
250
251 if (st->frule->match.dissector->used_keys ^ st->used_keys) {
252 NL_SET_ERR_MSG_MOD(st->fco->common.extack,
253 "Unsupported match item");
254 return -ENOENT;
255 }
256
257 return err;
258}
259
260static int sparx5_tc_flower_action_check(struct vcap_control *vctrl,
261 struct net_device *ndev,
262 struct flow_cls_offload *fco,
263 bool ingress)
264{
265 struct flow_rule *rule = flow_cls_offload_flow_rule(fco);
266 struct flow_action_entry *actent, *last_actent = NULL;
267 struct flow_action *act = &rule->action;
268 u64 action_mask = 0;
269 int idx;
270
271 if (!flow_action_has_entries(act)) {
272 NL_SET_ERR_MSG_MOD(fco->common.extack, "No actions");
273 return -EINVAL;
274 }
275
276 if (!flow_action_basic_hw_stats_check(act, fco->common.extack))
277 return -EOPNOTSUPP;
278
279 flow_action_for_each(idx, actent, act) {
280 if (action_mask & BIT(actent->id)) {
281 NL_SET_ERR_MSG_MOD(fco->common.extack,
282 "More actions of the same type");
283 return -EINVAL;
284 }
285 action_mask |= BIT(actent->id);
286 last_actent = actent; /* Save last action for later check */
287 }
288
289 /* Check if last action is a goto
290 * The last chain/lookup does not need to have a goto action
291 */
292 if (last_actent->id == FLOW_ACTION_GOTO) {
293 /* Check if the destination chain is in one of the VCAPs */
294 if (!vcap_is_next_lookup(vctrl, fco->common.chain_index,
295 last_actent->chain_index)) {
296 NL_SET_ERR_MSG_MOD(fco->common.extack,
297 "Invalid goto chain");
298 return -EINVAL;
299 }
300 } else if (!vcap_is_last_chain(vctrl, fco->common.chain_index,
301 ingress)) {
302 NL_SET_ERR_MSG_MOD(fco->common.extack,
303 "Last action must be 'goto'");
304 return -EINVAL;
305 }
306
307 /* Catch unsupported combinations of actions */
308 if (action_mask & BIT(FLOW_ACTION_TRAP) &&
309 action_mask & BIT(FLOW_ACTION_ACCEPT)) {
310 NL_SET_ERR_MSG_MOD(fco->common.extack,
311 "Cannot combine pass and trap action");
312 return -EOPNOTSUPP;
313 }
314
315 if (action_mask & BIT(FLOW_ACTION_VLAN_PUSH) &&
316 action_mask & BIT(FLOW_ACTION_VLAN_POP)) {
317 NL_SET_ERR_MSG_MOD(fco->common.extack,
318 "Cannot combine vlan push and pop action");
319 return -EOPNOTSUPP;
320 }
321
322 if (action_mask & BIT(FLOW_ACTION_VLAN_PUSH) &&
323 action_mask & BIT(FLOW_ACTION_VLAN_MANGLE)) {
324 NL_SET_ERR_MSG_MOD(fco->common.extack,
325 "Cannot combine vlan push and modify action");
326 return -EOPNOTSUPP;
327 }
328
329 if (action_mask & BIT(FLOW_ACTION_VLAN_POP) &&
330 action_mask & BIT(FLOW_ACTION_VLAN_MANGLE)) {
331 NL_SET_ERR_MSG_MOD(fco->common.extack,
332 "Cannot combine vlan pop and modify action");
333 return -EOPNOTSUPP;
334 }
335
336 return 0;
337}
338
339/* Add a rule counter action */
340static int sparx5_tc_add_rule_counter(struct vcap_admin *admin,
341 struct vcap_rule *vrule)
342{
343 int err;
344
345 switch (admin->vtype) {
346 case VCAP_TYPE_IS0:
347 break;
348 case VCAP_TYPE_ES0:
349 err = vcap_rule_mod_action_u32(vrule, VCAP_AF_ESDX,
350 vrule->id);
351 if (err)
352 return err;
353 vcap_rule_set_counter_id(vrule, vrule->id);
354 break;
355 case VCAP_TYPE_IS2:
356 case VCAP_TYPE_ES2:
357 err = vcap_rule_mod_action_u32(vrule, VCAP_AF_CNT_ID,
358 vrule->id);
359 if (err)
360 return err;
361 vcap_rule_set_counter_id(vrule, vrule->id);
362 break;
363 default:
364 pr_err("%s:%d: vcap type: %d not supported\n",
365 __func__, __LINE__, admin->vtype);
366 break;
367 }
368 return 0;
369}
370
371/* Collect all port keysets and apply the first of them, possibly wildcarded */
372static int sparx5_tc_select_protocol_keyset(struct net_device *ndev,
373 struct vcap_rule *vrule,
374 struct vcap_admin *admin,
375 u16 l3_proto,
376 struct sparx5_multiple_rules *multi)
377{
378 struct sparx5_port *port = netdev_priv(ndev);
379 struct vcap_keyset_list portkeysetlist = {};
380 enum vcap_keyfield_set portkeysets[10] = {};
381 struct vcap_keyset_list matches = {};
382 enum vcap_keyfield_set keysets[10];
383 int idx, jdx, err = 0, count = 0;
384 struct sparx5_wildcard_rule *mru;
385 const struct vcap_set *kinfo;
386 struct vcap_control *vctrl;
387
388 vctrl = port->sparx5->vcap_ctrl;
389
390 /* Find the keysets that the rule can use */
391 matches.keysets = keysets;
392 matches.max = ARRAY_SIZE(keysets);
393 if (!vcap_rule_find_keysets(vrule, &matches))
394 return -EINVAL;
395
396 /* Find the keysets that the port configuration supports */
397 portkeysetlist.max = ARRAY_SIZE(portkeysets);
398 portkeysetlist.keysets = portkeysets;
399 err = sparx5_vcap_get_port_keyset(ndev,
400 admin, vrule->vcap_chain_id,
401 l3_proto,
402 &portkeysetlist);
403 if (err)
404 return err;
405
406 /* Find the intersection of the two sets of keyset */
407 for (idx = 0; idx < portkeysetlist.cnt; ++idx) {
408 kinfo = vcap_keyfieldset(vctrl, admin->vtype,
409 portkeysetlist.keysets[idx]);
410 if (!kinfo)
411 continue;
412
413 /* Find a port keyset that matches the required keys
414 * If there are multiple keysets then compose a type id mask
415 */
416 for (jdx = 0; jdx < matches.cnt; ++jdx) {
417 if (portkeysetlist.keysets[idx] != matches.keysets[jdx])
418 continue;
419
420 mru = &multi->rule[kinfo->sw_per_item];
421 if (!mru->selected) {
422 mru->selected = true;
423 mru->keyset = portkeysetlist.keysets[idx];
424 mru->value = kinfo->type_id;
425 }
426 mru->value &= kinfo->type_id;
427 mru->mask |= kinfo->type_id;
428 ++count;
429 }
430 }
431 if (count == 0)
432 return -EPROTO;
433
434 if (l3_proto == ETH_P_ALL && count < portkeysetlist.cnt)
435 return -ENOENT;
436
437 for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) {
438 mru = &multi->rule[idx];
439 if (!mru->selected)
440 continue;
441
442 /* Align the mask to the combined value */
443 mru->mask ^= mru->value;
444 }
445
446 /* Set the chosen keyset on the rule and set a wildcarded type if there
447 * are more than one keyset
448 */
449 for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) {
450 mru = &multi->rule[idx];
451 if (!mru->selected)
452 continue;
453
454 vcap_set_rule_set_keyset(vrule, mru->keyset);
455 if (count > 1)
456 /* Some keysets do not have a type field */
457 vcap_rule_mod_key_u32(vrule, VCAP_KF_TYPE,
458 mru->value,
459 ~mru->mask);
460 mru->selected = false; /* mark as done */
461 break; /* Stop here and add more rules later */
462 }
463 return err;
464}
465
466static int sparx5_tc_add_rule_copy(struct vcap_control *vctrl,
467 struct flow_cls_offload *fco,
468 struct vcap_rule *erule,
469 struct vcap_admin *admin,
470 struct sparx5_wildcard_rule *rule)
471{
472 enum vcap_key_field keylist[] = {
473 VCAP_KF_IF_IGR_PORT_MASK,
474 VCAP_KF_IF_IGR_PORT_MASK_SEL,
475 VCAP_KF_IF_IGR_PORT_MASK_RNG,
476 VCAP_KF_LOOKUP_FIRST_IS,
477 VCAP_KF_TYPE,
478 };
479 struct vcap_rule *vrule;
480 int err;
481
482 /* Add an extra rule with a special user and the new keyset */
483 erule->user = VCAP_USER_TC_EXTRA;
484 vrule = vcap_copy_rule(erule);
485 if (IS_ERR(vrule))
486 return PTR_ERR(vrule);
487
488 /* Link the new rule to the existing rule with the cookie */
489 vrule->cookie = erule->cookie;
490 vcap_filter_rule_keys(vrule, keylist, ARRAY_SIZE(keylist), true);
491 err = vcap_set_rule_set_keyset(vrule, rule->keyset);
492 if (err) {
493 pr_err("%s:%d: could not set keyset %s in rule: %u\n",
494 __func__, __LINE__,
495 vcap_keyset_name(vctrl, rule->keyset),
496 vrule->id);
497 goto out;
498 }
499
500 /* Some keysets do not have a type field, so ignore return value */
501 vcap_rule_mod_key_u32(vrule, VCAP_KF_TYPE, rule->value, ~rule->mask);
502
503 err = vcap_set_rule_set_actionset(vrule, erule->actionset);
504 if (err)
505 goto out;
506
507 err = sparx5_tc_add_rule_counter(admin, vrule);
508 if (err)
509 goto out;
510
511 err = vcap_val_rule(vrule, ETH_P_ALL);
512 if (err) {
513 pr_err("%s:%d: could not validate rule: %u\n",
514 __func__, __LINE__, vrule->id);
515 vcap_set_tc_exterr(fco, vrule);
516 goto out;
517 }
518 err = vcap_add_rule(vrule);
519 if (err) {
520 pr_err("%s:%d: could not add rule: %u\n",
521 __func__, __LINE__, vrule->id);
522 goto out;
523 }
524out:
525 vcap_free_rule(vrule);
526 return err;
527}
528
529static int sparx5_tc_add_remaining_rules(struct vcap_control *vctrl,
530 struct flow_cls_offload *fco,
531 struct vcap_rule *erule,
532 struct vcap_admin *admin,
533 struct sparx5_multiple_rules *multi)
534{
535 int idx, err = 0;
536
537 for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) {
538 if (!multi->rule[idx].selected)
539 continue;
540
541 err = sparx5_tc_add_rule_copy(vctrl, fco, erule, admin,
542 &multi->rule[idx]);
543 if (err)
544 break;
545 }
546 return err;
547}
548
549/* Add the actionset that is the default for the VCAP type */
550static int sparx5_tc_set_actionset(struct vcap_admin *admin,
551 struct vcap_rule *vrule)
552{
553 enum vcap_actionfield_set aset;
554 int err = 0;
555
556 switch (admin->vtype) {
557 case VCAP_TYPE_IS0:
558 aset = VCAP_AFS_CLASSIFICATION;
559 break;
560 case VCAP_TYPE_IS2:
561 aset = VCAP_AFS_BASE_TYPE;
562 break;
563 case VCAP_TYPE_ES0:
564 aset = VCAP_AFS_ES0;
565 break;
566 case VCAP_TYPE_ES2:
567 aset = VCAP_AFS_BASE_TYPE;
568 break;
569 default:
570 pr_err("%s:%d: %s\n", __func__, __LINE__, "Invalid VCAP type");
571 return -EINVAL;
572 }
573 /* Do not overwrite any current actionset */
574 if (vrule->actionset == VCAP_AFS_NO_VALUE)
575 err = vcap_set_rule_set_actionset(vrule, aset);
576 return err;
577}
578
579/* Add the VCAP key to match on for a rule target value */
580static int sparx5_tc_add_rule_link_target(struct vcap_admin *admin,
581 struct vcap_rule *vrule,
582 int target_cid)
583{
584 int link_val = target_cid % VCAP_CID_LOOKUP_SIZE;
585 int err;
586
587 if (!link_val)
588 return 0;
589
590 switch (admin->vtype) {
591 case VCAP_TYPE_IS0:
592 /* Add NXT_IDX key for chaining rules between IS0 instances */
593 err = vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_GEN_IDX_SEL,
594 1, /* enable */
595 ~0);
596 if (err)
597 return err;
598 return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_GEN_IDX,
599 link_val, /* target */
600 ~0);
601 case VCAP_TYPE_IS2:
602 /* Add PAG key for chaining rules from IS0 */
603 return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_PAG,
604 link_val, /* target */
605 ~0);
606 case VCAP_TYPE_ES0:
607 case VCAP_TYPE_ES2:
608 /* Add ISDX key for chaining rules from IS0 */
609 return vcap_rule_add_key_u32(vrule, VCAP_KF_ISDX_CLS, link_val,
610 ~0);
611 default:
612 break;
613 }
614 return 0;
615}
616
617/* Add the VCAP action that adds a target value to a rule */
618static int sparx5_tc_add_rule_link(struct vcap_control *vctrl,
619 struct vcap_admin *admin,
620 struct vcap_rule *vrule,
621 int from_cid, int to_cid)
622{
623 struct vcap_admin *to_admin = vcap_find_admin(vctrl, to_cid);
624 int diff, err = 0;
625
626 if (!to_admin) {
627 pr_err("%s:%d: unsupported chain direction: %d\n",
628 __func__, __LINE__, to_cid);
629 return -EINVAL;
630 }
631
632 diff = vcap_chain_offset(vctrl, from_cid, to_cid);
633 if (!diff)
634 return 0;
635
636 if (admin->vtype == VCAP_TYPE_IS0 &&
637 to_admin->vtype == VCAP_TYPE_IS0) {
638 /* Between IS0 instances the G_IDX value is used */
639 err = vcap_rule_add_action_u32(vrule, VCAP_AF_NXT_IDX, diff);
640 if (err)
641 goto out;
642 err = vcap_rule_add_action_u32(vrule, VCAP_AF_NXT_IDX_CTRL,
643 1); /* Replace */
644 if (err)
645 goto out;
646 } else if (admin->vtype == VCAP_TYPE_IS0 &&
647 to_admin->vtype == VCAP_TYPE_IS2) {
648 /* Between IS0 and IS2 the PAG value is used */
649 err = vcap_rule_add_action_u32(vrule, VCAP_AF_PAG_VAL, diff);
650 if (err)
651 goto out;
652 err = vcap_rule_add_action_u32(vrule,
653 VCAP_AF_PAG_OVERRIDE_MASK,
654 0xff);
655 if (err)
656 goto out;
657 } else if (admin->vtype == VCAP_TYPE_IS0 &&
658 (to_admin->vtype == VCAP_TYPE_ES0 ||
659 to_admin->vtype == VCAP_TYPE_ES2)) {
660 /* Between IS0 and ES0/ES2 the ISDX value is used */
661 err = vcap_rule_add_action_u32(vrule, VCAP_AF_ISDX_VAL,
662 diff);
663 if (err)
664 goto out;
665 err = vcap_rule_add_action_bit(vrule,
666 VCAP_AF_ISDX_ADD_REPLACE_SEL,
667 VCAP_BIT_1);
668 if (err)
669 goto out;
670 } else {
671 pr_err("%s:%d: unsupported chain destination: %d\n",
672 __func__, __LINE__, to_cid);
673 err = -EOPNOTSUPP;
674 }
675out:
676 return err;
677}
678
679static int sparx5_tc_flower_parse_act_gate(struct sparx5_psfp_sg *sg,
680 struct flow_action_entry *act,
681 struct netlink_ext_ack *extack)
682{
683 int i;
684
685 if (act->gate.prio < -1 || act->gate.prio > SPX5_PSFP_SG_MAX_IPV) {
686 NL_SET_ERR_MSG_MOD(extack, "Invalid gate priority");
687 return -EINVAL;
688 }
689
690 if (act->gate.cycletime < SPX5_PSFP_SG_MIN_CYCLE_TIME_NS ||
691 act->gate.cycletime > SPX5_PSFP_SG_MAX_CYCLE_TIME_NS) {
692 NL_SET_ERR_MSG_MOD(extack, "Invalid gate cycletime");
693 return -EINVAL;
694 }
695
696 if (act->gate.cycletimeext > SPX5_PSFP_SG_MAX_CYCLE_TIME_NS) {
697 NL_SET_ERR_MSG_MOD(extack, "Invalid gate cycletimeext");
698 return -EINVAL;
699 }
700
701 if (act->gate.num_entries >= SPX5_PSFP_GCE_CNT) {
702 NL_SET_ERR_MSG_MOD(extack, "Invalid number of gate entries");
703 return -EINVAL;
704 }
705
706 sg->gate_state = true;
707 sg->ipv = act->gate.prio;
708 sg->num_entries = act->gate.num_entries;
709 sg->cycletime = act->gate.cycletime;
710 sg->cycletimeext = act->gate.cycletimeext;
711
712 for (i = 0; i < sg->num_entries; i++) {
713 sg->gce[i].gate_state = !!act->gate.entries[i].gate_state;
714 sg->gce[i].interval = act->gate.entries[i].interval;
715 sg->gce[i].ipv = act->gate.entries[i].ipv;
716 sg->gce[i].maxoctets = act->gate.entries[i].maxoctets;
717 }
718
719 return 0;
720}
721
722static int sparx5_tc_flower_parse_act_police(struct sparx5_policer *pol,
723 struct flow_action_entry *act,
724 struct netlink_ext_ack *extack)
725{
726 pol->type = SPX5_POL_SERVICE;
727 pol->rate = div_u64(act->police.rate_bytes_ps, 1000) * 8;
728 pol->burst = act->police.burst;
729 pol->idx = act->hw_index;
730
731 /* rate is now in kbit */
732 if (pol->rate > DIV_ROUND_UP(SPX5_SDLB_GROUP_RATE_MAX, 1000)) {
733 NL_SET_ERR_MSG_MOD(extack, "Maximum rate exceeded");
734 return -EINVAL;
735 }
736
737 if (act->police.exceed.act_id != FLOW_ACTION_DROP) {
738 NL_SET_ERR_MSG_MOD(extack, "Offload not supported when exceed action is not drop");
739 return -EOPNOTSUPP;
740 }
741
742 if (act->police.notexceed.act_id != FLOW_ACTION_PIPE &&
743 act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
744 NL_SET_ERR_MSG_MOD(extack, "Offload not supported when conform action is not pipe or ok");
745 return -EOPNOTSUPP;
746 }
747
748 return 0;
749}
750
751static int sparx5_tc_flower_psfp_setup(struct sparx5 *sparx5,
752 struct vcap_rule *vrule, int sg_idx,
753 int pol_idx, struct sparx5_psfp_sg *sg,
754 struct sparx5_psfp_fm *fm,
755 struct sparx5_psfp_sf *sf)
756{
757 u32 psfp_sfid = 0, psfp_fmid = 0, psfp_sgid = 0;
758 int ret;
759
760 /* Must always have a stream gate - max sdu (filter option) is evaluated
761 * after frames have passed the gate, so in case of only a policer, we
762 * allocate a stream gate that is always open.
763 */
764 if (sg_idx < 0) {
765 sg_idx = sparx5_pool_idx_to_id(SPX5_PSFP_SG_OPEN);
766 sg->ipv = 0; /* Disabled */
767 sg->cycletime = SPX5_PSFP_SG_CYCLE_TIME_DEFAULT;
768 sg->num_entries = 1;
769 sg->gate_state = 1; /* Open */
770 sg->gate_enabled = 1;
771 sg->gce[0].gate_state = 1;
772 sg->gce[0].interval = SPX5_PSFP_SG_CYCLE_TIME_DEFAULT;
773 sg->gce[0].ipv = 0;
774 sg->gce[0].maxoctets = 0; /* Disabled */
775 }
776
777 ret = sparx5_psfp_sg_add(sparx5, sg_idx, sg, &psfp_sgid);
778 if (ret < 0)
779 return ret;
780
781 if (pol_idx >= 0) {
782 /* Add new flow-meter */
783 ret = sparx5_psfp_fm_add(sparx5, pol_idx, fm, &psfp_fmid);
784 if (ret < 0)
785 return ret;
786 }
787
788 /* Map stream filter to stream gate */
789 sf->sgid = psfp_sgid;
790
791 /* Add new stream-filter and map it to a steam gate */
792 ret = sparx5_psfp_sf_add(sparx5, sf, &psfp_sfid);
793 if (ret < 0)
794 return ret;
795
796 /* Streams are classified by ISDX - map ISDX 1:1 to sfid for now. */
797 sparx5_isdx_conf_set(sparx5, psfp_sfid, psfp_sfid, psfp_fmid);
798
799 ret = vcap_rule_add_action_bit(vrule, VCAP_AF_ISDX_ADD_REPLACE_SEL,
800 VCAP_BIT_1);
801 if (ret)
802 return ret;
803
804 ret = vcap_rule_add_action_u32(vrule, VCAP_AF_ISDX_VAL, psfp_sfid);
805 if (ret)
806 return ret;
807
808 return 0;
809}
810
811/* Handle the action trap for a VCAP rule */
812static int sparx5_tc_action_trap(struct vcap_admin *admin,
813 struct vcap_rule *vrule,
814 struct flow_cls_offload *fco)
815{
816 int err = 0;
817
818 switch (admin->vtype) {
819 case VCAP_TYPE_IS2:
820 err = vcap_rule_add_action_bit(vrule,
821 VCAP_AF_CPU_COPY_ENA,
822 VCAP_BIT_1);
823 if (err)
824 break;
825 err = vcap_rule_add_action_u32(vrule,
826 VCAP_AF_CPU_QUEUE_NUM, 0);
827 if (err)
828 break;
829 err = vcap_rule_add_action_u32(vrule,
830 VCAP_AF_MASK_MODE,
831 SPX5_PMM_REPLACE_ALL);
832 break;
833 case VCAP_TYPE_ES0:
834 err = vcap_rule_add_action_u32(vrule,
835 VCAP_AF_FWD_SEL,
836 SPX5_FWSEL_REDIRECT_TO_LOOPBACK);
837 break;
838 case VCAP_TYPE_ES2:
839 err = vcap_rule_add_action_bit(vrule,
840 VCAP_AF_CPU_COPY_ENA,
841 VCAP_BIT_1);
842 if (err)
843 break;
844 err = vcap_rule_add_action_u32(vrule,
845 VCAP_AF_CPU_QUEUE_NUM, 0);
846 break;
847 default:
848 NL_SET_ERR_MSG_MOD(fco->common.extack,
849 "Trap action not supported in this VCAP");
850 err = -EOPNOTSUPP;
851 break;
852 }
853 return err;
854}
855
856static int sparx5_tc_action_vlan_pop(struct vcap_admin *admin,
857 struct vcap_rule *vrule,
858 struct flow_cls_offload *fco,
859 u16 tpid)
860{
861 int err = 0;
862
863 switch (admin->vtype) {
864 case VCAP_TYPE_ES0:
865 break;
866 default:
867 NL_SET_ERR_MSG_MOD(fco->common.extack,
868 "VLAN pop action not supported in this VCAP");
869 return -EOPNOTSUPP;
870 }
871
872 switch (tpid) {
873 case ETH_P_8021Q:
874 case ETH_P_8021AD:
875 err = vcap_rule_add_action_u32(vrule,
876 VCAP_AF_PUSH_OUTER_TAG,
877 SPX5_OTAG_UNTAG);
878 break;
879 default:
880 NL_SET_ERR_MSG_MOD(fco->common.extack,
881 "Invalid vlan proto");
882 err = -EINVAL;
883 }
884 return err;
885}
886
887static int sparx5_tc_action_vlan_modify(struct vcap_admin *admin,
888 struct vcap_rule *vrule,
889 struct flow_cls_offload *fco,
890 struct flow_action_entry *act,
891 u16 tpid)
892{
893 int err = 0;
894
895 switch (admin->vtype) {
896 case VCAP_TYPE_ES0:
897 err = vcap_rule_add_action_u32(vrule,
898 VCAP_AF_PUSH_OUTER_TAG,
899 SPX5_OTAG_TAG_A);
900 if (err)
901 return err;
902 break;
903 default:
904 NL_SET_ERR_MSG_MOD(fco->common.extack,
905 "VLAN modify action not supported in this VCAP");
906 return -EOPNOTSUPP;
907 }
908
909 switch (tpid) {
910 case ETH_P_8021Q:
911 err = vcap_rule_add_action_u32(vrule,
912 VCAP_AF_TAG_A_TPID_SEL,
913 SPX5_TPID_A_8100);
914 break;
915 case ETH_P_8021AD:
916 err = vcap_rule_add_action_u32(vrule,
917 VCAP_AF_TAG_A_TPID_SEL,
918 SPX5_TPID_A_88A8);
919 break;
920 default:
921 NL_SET_ERR_MSG_MOD(fco->common.extack,
922 "Invalid vlan proto");
923 err = -EINVAL;
924 }
925 if (err)
926 return err;
927
928 err = vcap_rule_add_action_u32(vrule,
929 VCAP_AF_TAG_A_VID_SEL,
930 SPX5_VID_A_VAL);
931 if (err)
932 return err;
933
934 err = vcap_rule_add_action_u32(vrule,
935 VCAP_AF_VID_A_VAL,
936 act->vlan.vid);
937 if (err)
938 return err;
939
940 err = vcap_rule_add_action_u32(vrule,
941 VCAP_AF_TAG_A_PCP_SEL,
942 SPX5_PCP_A_VAL);
943 if (err)
944 return err;
945
946 err = vcap_rule_add_action_u32(vrule,
947 VCAP_AF_PCP_A_VAL,
948 act->vlan.prio);
949 if (err)
950 return err;
951
952 return vcap_rule_add_action_u32(vrule,
953 VCAP_AF_TAG_A_DEI_SEL,
954 SPX5_DEI_A_CLASSIFIED);
955}
956
957static int sparx5_tc_action_vlan_push(struct vcap_admin *admin,
958 struct vcap_rule *vrule,
959 struct flow_cls_offload *fco,
960 struct flow_action_entry *act,
961 u16 tpid)
962{
963 u16 act_tpid = be16_to_cpu(act->vlan.proto);
964 int err = 0;
965
966 switch (admin->vtype) {
967 case VCAP_TYPE_ES0:
968 break;
969 default:
970 NL_SET_ERR_MSG_MOD(fco->common.extack,
971 "VLAN push action not supported in this VCAP");
972 return -EOPNOTSUPP;
973 }
974
975 if (tpid == ETH_P_8021AD) {
976 NL_SET_ERR_MSG_MOD(fco->common.extack,
977 "Cannot push on double tagged frames");
978 return -EOPNOTSUPP;
979 }
980
981 err = sparx5_tc_action_vlan_modify(admin, vrule, fco, act, act_tpid);
982 if (err)
983 return err;
984
985 switch (act_tpid) {
986 case ETH_P_8021Q:
987 break;
988 case ETH_P_8021AD:
989 /* Push classified tag as inner tag */
990 err = vcap_rule_add_action_u32(vrule,
991 VCAP_AF_PUSH_INNER_TAG,
992 SPX5_ITAG_PUSH_B_TAG);
993 if (err)
994 break;
995 err = vcap_rule_add_action_u32(vrule,
996 VCAP_AF_TAG_B_TPID_SEL,
997 SPX5_TPID_B_CLASSIFIED);
998 break;
999 default:
1000 NL_SET_ERR_MSG_MOD(fco->common.extack,
1001 "Invalid vlan proto");
1002 err = -EINVAL;
1003 }
1004 return err;
1005}
1006
1007/* Remove rule keys that may prevent templates from matching a keyset */
1008static void sparx5_tc_flower_simplify_rule(struct vcap_admin *admin,
1009 struct vcap_rule *vrule,
1010 u16 l3_proto)
1011{
1012 switch (admin->vtype) {
1013 case VCAP_TYPE_IS0:
1014 vcap_rule_rem_key(vrule, VCAP_KF_ETYPE);
1015 switch (l3_proto) {
1016 case ETH_P_IP:
1017 break;
1018 case ETH_P_IPV6:
1019 vcap_rule_rem_key(vrule, VCAP_KF_IP_SNAP_IS);
1020 break;
1021 default:
1022 break;
1023 }
1024 break;
1025 case VCAP_TYPE_ES2:
1026 switch (l3_proto) {
1027 case ETH_P_IP:
1028 if (vrule->keyset == VCAP_KFS_IP4_OTHER)
1029 vcap_rule_rem_key(vrule, VCAP_KF_TCP_IS);
1030 break;
1031 case ETH_P_IPV6:
1032 if (vrule->keyset == VCAP_KFS_IP6_STD)
1033 vcap_rule_rem_key(vrule, VCAP_KF_TCP_IS);
1034 vcap_rule_rem_key(vrule, VCAP_KF_IP4_IS);
1035 break;
1036 default:
1037 break;
1038 }
1039 break;
1040 case VCAP_TYPE_IS2:
1041 switch (l3_proto) {
1042 case ETH_P_IP:
1043 case ETH_P_IPV6:
1044 vcap_rule_rem_key(vrule, VCAP_KF_IP4_IS);
1045 break;
1046 default:
1047 break;
1048 }
1049 break;
1050 default:
1051 break;
1052 }
1053}
1054
1055static bool sparx5_tc_flower_use_template(struct net_device *ndev,
1056 struct flow_cls_offload *fco,
1057 struct vcap_admin *admin,
1058 struct vcap_rule *vrule)
1059{
1060 struct sparx5_port *port = netdev_priv(ndev);
1061 struct sparx5_tc_flower_template *ftp;
1062
1063 list_for_each_entry(ftp, &port->tc_templates, list) {
1064 if (ftp->cid != fco->common.chain_index)
1065 continue;
1066
1067 vcap_set_rule_set_keyset(vrule, ftp->keyset);
1068 sparx5_tc_flower_simplify_rule(admin, vrule, ftp->l3_proto);
1069 return true;
1070 }
1071 return false;
1072}
1073
1074static int sparx5_tc_flower_replace(struct net_device *ndev,
1075 struct flow_cls_offload *fco,
1076 struct vcap_admin *admin,
1077 bool ingress)
1078{
1079 struct sparx5_psfp_sf sf = { .max_sdu = SPX5_PSFP_SF_MAX_SDU };
1080 struct netlink_ext_ack *extack = fco->common.extack;
1081 int err, idx, tc_sg_idx = -1, tc_pol_idx = -1;
1082 struct vcap_tc_flower_parse_usage state = {
1083 .fco = fco,
1084 .l3_proto = ETH_P_ALL,
1085 .admin = admin,
1086 };
1087 struct sparx5_port *port = netdev_priv(ndev);
1088 struct sparx5_multiple_rules multi = {};
1089 struct sparx5 *sparx5 = port->sparx5;
1090 struct sparx5_psfp_sg sg = { 0 };
1091 struct sparx5_psfp_fm fm = { 0 };
1092 struct flow_action_entry *act;
1093 struct vcap_control *vctrl;
1094 struct flow_rule *frule;
1095 struct vcap_rule *vrule;
1096
1097 vctrl = port->sparx5->vcap_ctrl;
1098
1099 err = sparx5_tc_flower_action_check(vctrl, ndev, fco, ingress);
1100 if (err)
1101 return err;
1102
1103 vrule = vcap_alloc_rule(vctrl, ndev, fco->common.chain_index, VCAP_USER_TC,
1104 fco->common.prio, 0);
1105 if (IS_ERR(vrule))
1106 return PTR_ERR(vrule);
1107
1108 vrule->cookie = fco->cookie;
1109
1110 state.vrule = vrule;
1111 state.frule = flow_cls_offload_flow_rule(fco);
1112 err = sparx5_tc_use_dissectors(&state, admin, vrule);
1113 if (err)
1114 goto out;
1115
1116 err = sparx5_tc_add_rule_counter(admin, vrule);
1117 if (err)
1118 goto out;
1119
1120 err = sparx5_tc_add_rule_link_target(admin, vrule,
1121 fco->common.chain_index);
1122 if (err)
1123 goto out;
1124
1125 frule = flow_cls_offload_flow_rule(fco);
1126 flow_action_for_each(idx, act, &frule->action) {
1127 switch (act->id) {
1128 case FLOW_ACTION_GATE: {
1129 err = sparx5_tc_flower_parse_act_gate(&sg, act, extack);
1130 if (err < 0)
1131 goto out;
1132
1133 tc_sg_idx = act->hw_index;
1134
1135 break;
1136 }
1137 case FLOW_ACTION_POLICE: {
1138 err = sparx5_tc_flower_parse_act_police(&fm.pol, act,
1139 extack);
1140 if (err < 0)
1141 goto out;
1142
1143 tc_pol_idx = fm.pol.idx;
1144 sf.max_sdu = act->police.mtu;
1145
1146 break;
1147 }
1148 case FLOW_ACTION_TRAP:
1149 err = sparx5_tc_action_trap(admin, vrule, fco);
1150 if (err)
1151 goto out;
1152 break;
1153 case FLOW_ACTION_ACCEPT:
1154 err = sparx5_tc_set_actionset(admin, vrule);
1155 if (err)
1156 goto out;
1157 break;
1158 case FLOW_ACTION_GOTO:
1159 err = sparx5_tc_set_actionset(admin, vrule);
1160 if (err)
1161 goto out;
1162 sparx5_tc_add_rule_link(vctrl, admin, vrule,
1163 fco->common.chain_index,
1164 act->chain_index);
1165 break;
1166 case FLOW_ACTION_VLAN_POP:
1167 err = sparx5_tc_action_vlan_pop(admin, vrule, fco,
1168 state.tpid);
1169 if (err)
1170 goto out;
1171 break;
1172 case FLOW_ACTION_VLAN_PUSH:
1173 err = sparx5_tc_action_vlan_push(admin, vrule, fco,
1174 act, state.tpid);
1175 if (err)
1176 goto out;
1177 break;
1178 case FLOW_ACTION_VLAN_MANGLE:
1179 err = sparx5_tc_action_vlan_modify(admin, vrule, fco,
1180 act, state.tpid);
1181 if (err)
1182 goto out;
1183 break;
1184 default:
1185 NL_SET_ERR_MSG_MOD(fco->common.extack,
1186 "Unsupported TC action");
1187 err = -EOPNOTSUPP;
1188 goto out;
1189 }
1190 }
1191
1192 /* Setup PSFP */
1193 if (tc_sg_idx >= 0 || tc_pol_idx >= 0) {
1194 err = sparx5_tc_flower_psfp_setup(sparx5, vrule, tc_sg_idx,
1195 tc_pol_idx, &sg, &fm, &sf);
1196 if (err)
1197 goto out;
1198 }
1199
1200 if (!sparx5_tc_flower_use_template(ndev, fco, admin, vrule)) {
1201 err = sparx5_tc_select_protocol_keyset(ndev, vrule, admin,
1202 state.l3_proto, &multi);
1203 if (err) {
1204 NL_SET_ERR_MSG_MOD(fco->common.extack,
1205 "No matching port keyset for filter protocol and keys");
1206 goto out;
1207 }
1208 }
1209
1210 /* provide the l3 protocol to guide the keyset selection */
1211 err = vcap_val_rule(vrule, state.l3_proto);
1212 if (err) {
1213 vcap_set_tc_exterr(fco, vrule);
1214 goto out;
1215 }
1216 err = vcap_add_rule(vrule);
1217 if (err)
1218 NL_SET_ERR_MSG_MOD(fco->common.extack,
1219 "Could not add the filter");
1220
1221 if (state.l3_proto == ETH_P_ALL)
1222 err = sparx5_tc_add_remaining_rules(vctrl, fco, vrule, admin,
1223 &multi);
1224
1225out:
1226 vcap_free_rule(vrule);
1227 return err;
1228}
1229
1230static void sparx5_tc_free_psfp_resources(struct sparx5 *sparx5,
1231 struct vcap_rule *vrule)
1232{
1233 struct vcap_client_actionfield *afield;
1234 u32 isdx, sfid, sgid, fmid;
1235
1236 /* Check if VCAP_AF_ISDX_VAL action is set for this rule - and if
1237 * it is used for stream and/or flow-meter classification.
1238 */
1239 afield = vcap_find_actionfield(vrule, VCAP_AF_ISDX_VAL);
1240 if (!afield)
1241 return;
1242
1243 isdx = afield->data.u32.value;
1244 sfid = sparx5_psfp_isdx_get_sf(sparx5, isdx);
1245
1246 if (!sfid)
1247 return;
1248
1249 fmid = sparx5_psfp_isdx_get_fm(sparx5, isdx);
1250 sgid = sparx5_psfp_sf_get_sg(sparx5, sfid);
1251
1252 if (fmid && sparx5_psfp_fm_del(sparx5, fmid) < 0)
1253 pr_err("%s:%d Could not delete invalid fmid: %d", __func__,
1254 __LINE__, fmid);
1255
1256 if (sgid && sparx5_psfp_sg_del(sparx5, sgid) < 0)
1257 pr_err("%s:%d Could not delete invalid sgid: %d", __func__,
1258 __LINE__, sgid);
1259
1260 if (sparx5_psfp_sf_del(sparx5, sfid) < 0)
1261 pr_err("%s:%d Could not delete invalid sfid: %d", __func__,
1262 __LINE__, sfid);
1263
1264 sparx5_isdx_conf_set(sparx5, isdx, 0, 0);
1265}
1266
1267static int sparx5_tc_free_rule_resources(struct net_device *ndev,
1268 struct vcap_control *vctrl,
1269 int rule_id)
1270{
1271 struct sparx5_port *port = netdev_priv(ndev);
1272 struct sparx5 *sparx5 = port->sparx5;
1273 struct vcap_rule *vrule;
1274 int ret = 0;
1275
1276 vrule = vcap_get_rule(vctrl, rule_id);
1277 if (IS_ERR(vrule))
1278 return -EINVAL;
1279
1280 sparx5_tc_free_psfp_resources(sparx5, vrule);
1281
1282 vcap_free_rule(vrule);
1283 return ret;
1284}
1285
1286static int sparx5_tc_flower_destroy(struct net_device *ndev,
1287 struct flow_cls_offload *fco,
1288 struct vcap_admin *admin)
1289{
1290 struct sparx5_port *port = netdev_priv(ndev);
1291 int err = -ENOENT, count = 0, rule_id;
1292 struct vcap_control *vctrl;
1293
1294 vctrl = port->sparx5->vcap_ctrl;
1295 while (true) {
1296 rule_id = vcap_lookup_rule_by_cookie(vctrl, fco->cookie);
1297 if (rule_id <= 0)
1298 break;
1299 if (count == 0) {
1300 /* Resources are attached to the first rule of
1301 * a set of rules. Only works if the rules are
1302 * in the correct order.
1303 */
1304 err = sparx5_tc_free_rule_resources(ndev, vctrl,
1305 rule_id);
1306 if (err)
1307 pr_err("%s:%d: could not free resources %d\n",
1308 __func__, __LINE__, rule_id);
1309 }
1310 err = vcap_del_rule(vctrl, ndev, rule_id);
1311 if (err) {
1312 pr_err("%s:%d: could not delete rule %d\n",
1313 __func__, __LINE__, rule_id);
1314 break;
1315 }
1316 }
1317 return err;
1318}
1319
1320static int sparx5_tc_flower_stats(struct net_device *ndev,
1321 struct flow_cls_offload *fco,
1322 struct vcap_admin *admin)
1323{
1324 struct sparx5_port *port = netdev_priv(ndev);
1325 struct vcap_counter ctr = {};
1326 struct vcap_control *vctrl;
1327 ulong lastused = 0;
1328 int err;
1329
1330 vctrl = port->sparx5->vcap_ctrl;
1331 err = vcap_get_rule_count_by_cookie(vctrl, &ctr, fco->cookie);
1332 if (err)
1333 return err;
1334 flow_stats_update(&fco->stats, 0x0, ctr.value, 0, lastused,
1335 FLOW_ACTION_HW_STATS_IMMEDIATE);
1336 return err;
1337}
1338
1339static int sparx5_tc_flower_template_create(struct net_device *ndev,
1340 struct flow_cls_offload *fco,
1341 struct vcap_admin *admin)
1342{
1343 struct sparx5_port *port = netdev_priv(ndev);
1344 struct vcap_tc_flower_parse_usage state = {
1345 .fco = fco,
1346 .l3_proto = ETH_P_ALL,
1347 .admin = admin,
1348 };
1349 struct sparx5_tc_flower_template *ftp;
1350 struct vcap_keyset_list kslist = {};
1351 enum vcap_keyfield_set keysets[10];
1352 struct vcap_control *vctrl;
1353 struct vcap_rule *vrule;
1354 int count, err;
1355
1356 if (admin->vtype == VCAP_TYPE_ES0) {
1357 pr_err("%s:%d: %s\n", __func__, __LINE__,
1358 "VCAP does not support templates");
1359 return -EINVAL;
1360 }
1361
1362 count = vcap_admin_rule_count(admin, fco->common.chain_index);
1363 if (count > 0) {
1364 pr_err("%s:%d: %s\n", __func__, __LINE__,
1365 "Filters are already present");
1366 return -EBUSY;
1367 }
1368
1369 ftp = kzalloc(sizeof(*ftp), GFP_KERNEL);
1370 if (!ftp)
1371 return -ENOMEM;
1372
1373 ftp->cid = fco->common.chain_index;
1374 ftp->orig = VCAP_KFS_NO_VALUE;
1375 ftp->keyset = VCAP_KFS_NO_VALUE;
1376
1377 vctrl = port->sparx5->vcap_ctrl;
1378 vrule = vcap_alloc_rule(vctrl, ndev, fco->common.chain_index,
1379 VCAP_USER_TC, fco->common.prio, 0);
1380 if (IS_ERR(vrule)) {
1381 err = PTR_ERR(vrule);
1382 goto err_rule;
1383 }
1384
1385 state.vrule = vrule;
1386 state.frule = flow_cls_offload_flow_rule(fco);
1387 err = sparx5_tc_use_dissectors(&state, admin, vrule);
1388 if (err) {
1389 pr_err("%s:%d: key error: %d\n", __func__, __LINE__, err);
1390 goto out;
1391 }
1392
1393 ftp->l3_proto = state.l3_proto;
1394
1395 sparx5_tc_flower_simplify_rule(admin, vrule, state.l3_proto);
1396
1397 /* Find the keysets that the rule can use */
1398 kslist.keysets = keysets;
1399 kslist.max = ARRAY_SIZE(keysets);
1400 if (!vcap_rule_find_keysets(vrule, &kslist)) {
1401 pr_err("%s:%d: %s\n", __func__, __LINE__,
1402 "Could not find a suitable keyset");
1403 err = -ENOENT;
1404 goto out;
1405 }
1406
1407 ftp->keyset = vcap_select_min_rule_keyset(vctrl, admin->vtype, &kslist);
1408 kslist.cnt = 0;
1409 sparx5_vcap_set_port_keyset(ndev, admin, fco->common.chain_index,
1410 state.l3_proto,
1411 ftp->keyset,
1412 &kslist);
1413
1414 if (kslist.cnt > 0)
1415 ftp->orig = kslist.keysets[0];
1416
1417 /* Store new template */
1418 list_add_tail(&ftp->list, &port->tc_templates);
1419 vcap_free_rule(vrule);
1420 return 0;
1421
1422out:
1423 vcap_free_rule(vrule);
1424err_rule:
1425 kfree(ftp);
1426 return err;
1427}
1428
1429static int sparx5_tc_flower_template_destroy(struct net_device *ndev,
1430 struct flow_cls_offload *fco,
1431 struct vcap_admin *admin)
1432{
1433 struct sparx5_port *port = netdev_priv(ndev);
1434 struct sparx5_tc_flower_template *ftp, *tmp;
1435 int err = -ENOENT;
1436
1437 /* Rules using the template are removed by the tc framework */
1438 list_for_each_entry_safe(ftp, tmp, &port->tc_templates, list) {
1439 if (ftp->cid != fco->common.chain_index)
1440 continue;
1441
1442 sparx5_vcap_set_port_keyset(ndev, admin,
1443 fco->common.chain_index,
1444 ftp->l3_proto, ftp->orig,
1445 NULL);
1446 list_del(&ftp->list);
1447 kfree(ftp);
1448 break;
1449 }
1450 return err;
1451}
1452
1453int sparx5_tc_flower(struct net_device *ndev, struct flow_cls_offload *fco,
1454 bool ingress)
1455{
1456 struct sparx5_port *port = netdev_priv(ndev);
1457 struct vcap_control *vctrl;
1458 struct vcap_admin *admin;
1459 int err = -EINVAL;
1460
1461 /* Get vcap instance from the chain id */
1462 vctrl = port->sparx5->vcap_ctrl;
1463 admin = vcap_find_admin(vctrl, fco->common.chain_index);
1464 if (!admin) {
1465 NL_SET_ERR_MSG_MOD(fco->common.extack, "Invalid chain");
1466 return err;
1467 }
1468
1469 switch (fco->command) {
1470 case FLOW_CLS_REPLACE:
1471 return sparx5_tc_flower_replace(ndev, fco, admin, ingress);
1472 case FLOW_CLS_DESTROY:
1473 return sparx5_tc_flower_destroy(ndev, fco, admin);
1474 case FLOW_CLS_STATS:
1475 return sparx5_tc_flower_stats(ndev, fco, admin);
1476 case FLOW_CLS_TMPLT_CREATE:
1477 return sparx5_tc_flower_template_create(ndev, fco, admin);
1478 case FLOW_CLS_TMPLT_DESTROY:
1479 return sparx5_tc_flower_template_destroy(ndev, fco, admin);
1480 default:
1481 return -EOPNOTSUPP;
1482 }
1483}
1// SPDX-License-Identifier: GPL-2.0+
2/* Microchip VCAP API
3 *
4 * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.
5 */
6
7#include <net/tcp.h>
8
9#include "sparx5_tc.h"
10#include "vcap_api.h"
11#include "vcap_api_client.h"
12#include "sparx5_main.h"
13#include "sparx5_vcap_impl.h"
14
15#define SPX5_MAX_RULE_SIZE 13 /* allows X1, X2, X4, X6 and X12 rules */
16
17/* Collect keysets and type ids for multiple rules per size */
18struct sparx5_wildcard_rule {
19 bool selected;
20 u8 value;
21 u8 mask;
22 enum vcap_keyfield_set keyset;
23};
24
25struct sparx5_multiple_rules {
26 struct sparx5_wildcard_rule rule[SPX5_MAX_RULE_SIZE];
27};
28
29struct sparx5_tc_flower_parse_usage {
30 struct flow_cls_offload *fco;
31 struct flow_rule *frule;
32 struct vcap_rule *vrule;
33 u16 l3_proto;
34 u8 l4_proto;
35 unsigned int used_keys;
36};
37
38struct sparx5_tc_rule_pkt_cnt {
39 u64 cookie;
40 u32 pkts;
41};
42
43/* These protocols have dedicated keysets in IS2 and a TC dissector
44 * ETH_P_ARP does not have a TC dissector
45 */
46static u16 sparx5_tc_known_etypes[] = {
47 ETH_P_ALL,
48 ETH_P_ARP,
49 ETH_P_IP,
50 ETH_P_IPV6,
51};
52
53enum sparx5_is2_arp_opcode {
54 SPX5_IS2_ARP_REQUEST,
55 SPX5_IS2_ARP_REPLY,
56 SPX5_IS2_RARP_REQUEST,
57 SPX5_IS2_RARP_REPLY,
58};
59
60enum tc_arp_opcode {
61 TC_ARP_OP_RESERVED,
62 TC_ARP_OP_REQUEST,
63 TC_ARP_OP_REPLY,
64};
65
66static bool sparx5_tc_is_known_etype(u16 etype)
67{
68 int idx;
69
70 /* For now this only knows about IS2 traffic classification */
71 for (idx = 0; idx < ARRAY_SIZE(sparx5_tc_known_etypes); ++idx)
72 if (sparx5_tc_known_etypes[idx] == etype)
73 return true;
74
75 return false;
76}
77
78static int sparx5_tc_flower_handler_ethaddr_usage(struct sparx5_tc_flower_parse_usage *st)
79{
80 enum vcap_key_field smac_key = VCAP_KF_L2_SMAC;
81 enum vcap_key_field dmac_key = VCAP_KF_L2_DMAC;
82 struct flow_match_eth_addrs match;
83 struct vcap_u48_key smac, dmac;
84 int err = 0;
85
86 flow_rule_match_eth_addrs(st->frule, &match);
87
88 if (!is_zero_ether_addr(match.mask->src)) {
89 vcap_netbytes_copy(smac.value, match.key->src, ETH_ALEN);
90 vcap_netbytes_copy(smac.mask, match.mask->src, ETH_ALEN);
91 err = vcap_rule_add_key_u48(st->vrule, smac_key, &smac);
92 if (err)
93 goto out;
94 }
95
96 if (!is_zero_ether_addr(match.mask->dst)) {
97 vcap_netbytes_copy(dmac.value, match.key->dst, ETH_ALEN);
98 vcap_netbytes_copy(dmac.mask, match.mask->dst, ETH_ALEN);
99 err = vcap_rule_add_key_u48(st->vrule, dmac_key, &dmac);
100 if (err)
101 goto out;
102 }
103
104 st->used_keys |= BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS);
105
106 return err;
107
108out:
109 NL_SET_ERR_MSG_MOD(st->fco->common.extack, "eth_addr parse error");
110 return err;
111}
112
113static int
114sparx5_tc_flower_handler_ipv4_usage(struct sparx5_tc_flower_parse_usage *st)
115{
116 int err = 0;
117
118 if (st->l3_proto == ETH_P_IP) {
119 struct flow_match_ipv4_addrs mt;
120
121 flow_rule_match_ipv4_addrs(st->frule, &mt);
122 if (mt.mask->src) {
123 err = vcap_rule_add_key_u32(st->vrule,
124 VCAP_KF_L3_IP4_SIP,
125 be32_to_cpu(mt.key->src),
126 be32_to_cpu(mt.mask->src));
127 if (err)
128 goto out;
129 }
130 if (mt.mask->dst) {
131 err = vcap_rule_add_key_u32(st->vrule,
132 VCAP_KF_L3_IP4_DIP,
133 be32_to_cpu(mt.key->dst),
134 be32_to_cpu(mt.mask->dst));
135 if (err)
136 goto out;
137 }
138 }
139
140 st->used_keys |= BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS);
141
142 return err;
143
144out:
145 NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ipv4_addr parse error");
146 return err;
147}
148
149static int
150sparx5_tc_flower_handler_ipv6_usage(struct sparx5_tc_flower_parse_usage *st)
151{
152 int err = 0;
153
154 if (st->l3_proto == ETH_P_IPV6) {
155 struct flow_match_ipv6_addrs mt;
156 struct vcap_u128_key sip;
157 struct vcap_u128_key dip;
158
159 flow_rule_match_ipv6_addrs(st->frule, &mt);
160 /* Check if address masks are non-zero */
161 if (!ipv6_addr_any(&mt.mask->src)) {
162 vcap_netbytes_copy(sip.value, mt.key->src.s6_addr, 16);
163 vcap_netbytes_copy(sip.mask, mt.mask->src.s6_addr, 16);
164 err = vcap_rule_add_key_u128(st->vrule,
165 VCAP_KF_L3_IP6_SIP, &sip);
166 if (err)
167 goto out;
168 }
169 if (!ipv6_addr_any(&mt.mask->dst)) {
170 vcap_netbytes_copy(dip.value, mt.key->dst.s6_addr, 16);
171 vcap_netbytes_copy(dip.mask, mt.mask->dst.s6_addr, 16);
172 err = vcap_rule_add_key_u128(st->vrule,
173 VCAP_KF_L3_IP6_DIP, &dip);
174 if (err)
175 goto out;
176 }
177 }
178 st->used_keys |= BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS);
179 return err;
180out:
181 NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ipv6_addr parse error");
182 return err;
183}
184
185static int
186sparx5_tc_flower_handler_control_usage(struct sparx5_tc_flower_parse_usage *st)
187{
188 struct flow_match_control mt;
189 u32 value, mask;
190 int err = 0;
191
192 flow_rule_match_control(st->frule, &mt);
193
194 if (mt.mask->flags) {
195 if (mt.mask->flags & FLOW_DIS_FIRST_FRAG) {
196 if (mt.key->flags & FLOW_DIS_FIRST_FRAG) {
197 value = 1; /* initial fragment */
198 mask = 0x3;
199 } else {
200 if (mt.mask->flags & FLOW_DIS_IS_FRAGMENT) {
201 value = 3; /* follow up fragment */
202 mask = 0x3;
203 } else {
204 value = 0; /* no fragment */
205 mask = 0x3;
206 }
207 }
208 } else {
209 if (mt.mask->flags & FLOW_DIS_IS_FRAGMENT) {
210 value = 3; /* follow up fragment */
211 mask = 0x3;
212 } else {
213 value = 0; /* no fragment */
214 mask = 0x3;
215 }
216 }
217
218 err = vcap_rule_add_key_u32(st->vrule,
219 VCAP_KF_L3_FRAGMENT_TYPE,
220 value, mask);
221 if (err)
222 goto out;
223 }
224
225 st->used_keys |= BIT(FLOW_DISSECTOR_KEY_CONTROL);
226
227 return err;
228
229out:
230 NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_frag parse error");
231 return err;
232}
233
234static int
235sparx5_tc_flower_handler_portnum_usage(struct sparx5_tc_flower_parse_usage *st)
236{
237 struct flow_match_ports mt;
238 u16 value, mask;
239 int err = 0;
240
241 flow_rule_match_ports(st->frule, &mt);
242
243 if (mt.mask->src) {
244 value = be16_to_cpu(mt.key->src);
245 mask = be16_to_cpu(mt.mask->src);
246 err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L4_SPORT, value,
247 mask);
248 if (err)
249 goto out;
250 }
251
252 if (mt.mask->dst) {
253 value = be16_to_cpu(mt.key->dst);
254 mask = be16_to_cpu(mt.mask->dst);
255 err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L4_DPORT, value,
256 mask);
257 if (err)
258 goto out;
259 }
260
261 st->used_keys |= BIT(FLOW_DISSECTOR_KEY_PORTS);
262
263 return err;
264
265out:
266 NL_SET_ERR_MSG_MOD(st->fco->common.extack, "port parse error");
267 return err;
268}
269
270static int
271sparx5_tc_flower_handler_basic_usage(struct sparx5_tc_flower_parse_usage *st)
272{
273 struct flow_match_basic mt;
274 int err = 0;
275
276 flow_rule_match_basic(st->frule, &mt);
277
278 if (mt.mask->n_proto) {
279 st->l3_proto = be16_to_cpu(mt.key->n_proto);
280 if (!sparx5_tc_is_known_etype(st->l3_proto)) {
281 err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_ETYPE,
282 st->l3_proto, ~0);
283 if (err)
284 goto out;
285 } else if (st->l3_proto == ETH_P_IP) {
286 err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS,
287 VCAP_BIT_1);
288 if (err)
289 goto out;
290 } else if (st->l3_proto == ETH_P_IPV6) {
291 err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS,
292 VCAP_BIT_0);
293 if (err)
294 goto out;
295 }
296 }
297
298 if (mt.mask->ip_proto) {
299 st->l4_proto = mt.key->ip_proto;
300 if (st->l4_proto == IPPROTO_TCP) {
301 err = vcap_rule_add_key_bit(st->vrule,
302 VCAP_KF_TCP_IS,
303 VCAP_BIT_1);
304 if (err)
305 goto out;
306 } else if (st->l4_proto == IPPROTO_UDP) {
307 err = vcap_rule_add_key_bit(st->vrule,
308 VCAP_KF_TCP_IS,
309 VCAP_BIT_0);
310 if (err)
311 goto out;
312 } else {
313 err = vcap_rule_add_key_u32(st->vrule,
314 VCAP_KF_L3_IP_PROTO,
315 st->l4_proto, ~0);
316 if (err)
317 goto out;
318 }
319 }
320
321 st->used_keys |= BIT(FLOW_DISSECTOR_KEY_BASIC);
322
323 return err;
324
325out:
326 NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_proto parse error");
327 return err;
328}
329
330static int
331sparx5_tc_flower_handler_vlan_usage(struct sparx5_tc_flower_parse_usage *st)
332{
333 enum vcap_key_field vid_key = VCAP_KF_8021Q_VID_CLS;
334 enum vcap_key_field pcp_key = VCAP_KF_8021Q_PCP_CLS;
335 struct flow_match_vlan mt;
336 int err;
337
338 flow_rule_match_vlan(st->frule, &mt);
339
340 if (mt.mask->vlan_id) {
341 err = vcap_rule_add_key_u32(st->vrule, vid_key,
342 mt.key->vlan_id,
343 mt.mask->vlan_id);
344 if (err)
345 goto out;
346 }
347
348 if (mt.mask->vlan_priority) {
349 err = vcap_rule_add_key_u32(st->vrule, pcp_key,
350 mt.key->vlan_priority,
351 mt.mask->vlan_priority);
352 if (err)
353 goto out;
354 }
355
356 st->used_keys |= BIT(FLOW_DISSECTOR_KEY_VLAN);
357
358 return 0;
359out:
360 NL_SET_ERR_MSG_MOD(st->fco->common.extack, "vlan parse error");
361 return err;
362}
363
364static int
365sparx5_tc_flower_handler_tcp_usage(struct sparx5_tc_flower_parse_usage *st)
366{
367 struct flow_match_tcp mt;
368 u16 tcp_flags_mask;
369 u16 tcp_flags_key;
370 enum vcap_bit val;
371 int err = 0;
372
373 flow_rule_match_tcp(st->frule, &mt);
374 tcp_flags_key = be16_to_cpu(mt.key->flags);
375 tcp_flags_mask = be16_to_cpu(mt.mask->flags);
376
377 if (tcp_flags_mask & TCPHDR_FIN) {
378 val = VCAP_BIT_0;
379 if (tcp_flags_key & TCPHDR_FIN)
380 val = VCAP_BIT_1;
381 err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_FIN, val);
382 if (err)
383 goto out;
384 }
385
386 if (tcp_flags_mask & TCPHDR_SYN) {
387 val = VCAP_BIT_0;
388 if (tcp_flags_key & TCPHDR_SYN)
389 val = VCAP_BIT_1;
390 err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_SYN, val);
391 if (err)
392 goto out;
393 }
394
395 if (tcp_flags_mask & TCPHDR_RST) {
396 val = VCAP_BIT_0;
397 if (tcp_flags_key & TCPHDR_RST)
398 val = VCAP_BIT_1;
399 err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_RST, val);
400 if (err)
401 goto out;
402 }
403
404 if (tcp_flags_mask & TCPHDR_PSH) {
405 val = VCAP_BIT_0;
406 if (tcp_flags_key & TCPHDR_PSH)
407 val = VCAP_BIT_1;
408 err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_PSH, val);
409 if (err)
410 goto out;
411 }
412
413 if (tcp_flags_mask & TCPHDR_ACK) {
414 val = VCAP_BIT_0;
415 if (tcp_flags_key & TCPHDR_ACK)
416 val = VCAP_BIT_1;
417 err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_ACK, val);
418 if (err)
419 goto out;
420 }
421
422 if (tcp_flags_mask & TCPHDR_URG) {
423 val = VCAP_BIT_0;
424 if (tcp_flags_key & TCPHDR_URG)
425 val = VCAP_BIT_1;
426 err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_URG, val);
427 if (err)
428 goto out;
429 }
430
431 st->used_keys |= BIT(FLOW_DISSECTOR_KEY_TCP);
432
433 return err;
434
435out:
436 NL_SET_ERR_MSG_MOD(st->fco->common.extack, "tcp_flags parse error");
437 return err;
438}
439
440static int
441sparx5_tc_flower_handler_arp_usage(struct sparx5_tc_flower_parse_usage *st)
442{
443 struct flow_match_arp mt;
444 u16 value, mask;
445 u32 ipval, ipmsk;
446 int err;
447
448 flow_rule_match_arp(st->frule, &mt);
449
450 if (mt.mask->op) {
451 mask = 0x3;
452 if (st->l3_proto == ETH_P_ARP) {
453 value = mt.key->op == TC_ARP_OP_REQUEST ?
454 SPX5_IS2_ARP_REQUEST :
455 SPX5_IS2_ARP_REPLY;
456 } else { /* RARP */
457 value = mt.key->op == TC_ARP_OP_REQUEST ?
458 SPX5_IS2_RARP_REQUEST :
459 SPX5_IS2_RARP_REPLY;
460 }
461 err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_ARP_OPCODE,
462 value, mask);
463 if (err)
464 goto out;
465 }
466
467 /* The IS2 ARP keyset does not support ARP hardware addresses */
468 if (!is_zero_ether_addr(mt.mask->sha) ||
469 !is_zero_ether_addr(mt.mask->tha)) {
470 err = -EINVAL;
471 goto out;
472 }
473
474 if (mt.mask->sip) {
475 ipval = be32_to_cpu((__force __be32)mt.key->sip);
476 ipmsk = be32_to_cpu((__force __be32)mt.mask->sip);
477
478 err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L3_IP4_SIP,
479 ipval, ipmsk);
480 if (err)
481 goto out;
482 }
483
484 if (mt.mask->tip) {
485 ipval = be32_to_cpu((__force __be32)mt.key->tip);
486 ipmsk = be32_to_cpu((__force __be32)mt.mask->tip);
487
488 err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L3_IP4_DIP,
489 ipval, ipmsk);
490 if (err)
491 goto out;
492 }
493
494 st->used_keys |= BIT(FLOW_DISSECTOR_KEY_ARP);
495
496 return 0;
497
498out:
499 NL_SET_ERR_MSG_MOD(st->fco->common.extack, "arp parse error");
500 return err;
501}
502
503static int
504sparx5_tc_flower_handler_ip_usage(struct sparx5_tc_flower_parse_usage *st)
505{
506 struct flow_match_ip mt;
507 int err = 0;
508
509 flow_rule_match_ip(st->frule, &mt);
510
511 if (mt.mask->tos) {
512 err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L3_TOS,
513 mt.key->tos,
514 mt.mask->tos);
515 if (err)
516 goto out;
517 }
518
519 st->used_keys |= BIT(FLOW_DISSECTOR_KEY_IP);
520
521 return err;
522
523out:
524 NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_tos parse error");
525 return err;
526}
527
528static int (*sparx5_tc_flower_usage_handlers[])(struct sparx5_tc_flower_parse_usage *st) = {
529 [FLOW_DISSECTOR_KEY_ETH_ADDRS] = sparx5_tc_flower_handler_ethaddr_usage,
530 [FLOW_DISSECTOR_KEY_IPV4_ADDRS] = sparx5_tc_flower_handler_ipv4_usage,
531 [FLOW_DISSECTOR_KEY_IPV6_ADDRS] = sparx5_tc_flower_handler_ipv6_usage,
532 [FLOW_DISSECTOR_KEY_CONTROL] = sparx5_tc_flower_handler_control_usage,
533 [FLOW_DISSECTOR_KEY_PORTS] = sparx5_tc_flower_handler_portnum_usage,
534 [FLOW_DISSECTOR_KEY_BASIC] = sparx5_tc_flower_handler_basic_usage,
535 [FLOW_DISSECTOR_KEY_VLAN] = sparx5_tc_flower_handler_vlan_usage,
536 [FLOW_DISSECTOR_KEY_TCP] = sparx5_tc_flower_handler_tcp_usage,
537 [FLOW_DISSECTOR_KEY_ARP] = sparx5_tc_flower_handler_arp_usage,
538 [FLOW_DISSECTOR_KEY_IP] = sparx5_tc_flower_handler_ip_usage,
539};
540
541static int sparx5_tc_use_dissectors(struct flow_cls_offload *fco,
542 struct vcap_admin *admin,
543 struct vcap_rule *vrule,
544 u16 *l3_proto)
545{
546 struct sparx5_tc_flower_parse_usage state = {
547 .fco = fco,
548 .vrule = vrule,
549 .l3_proto = ETH_P_ALL,
550 };
551 int idx, err = 0;
552
553 state.frule = flow_cls_offload_flow_rule(fco);
554 for (idx = 0; idx < ARRAY_SIZE(sparx5_tc_flower_usage_handlers); ++idx) {
555 if (!flow_rule_match_key(state.frule, idx))
556 continue;
557 if (!sparx5_tc_flower_usage_handlers[idx])
558 continue;
559 err = sparx5_tc_flower_usage_handlers[idx](&state);
560 if (err)
561 return err;
562 }
563
564 if (state.frule->match.dissector->used_keys ^ state.used_keys) {
565 NL_SET_ERR_MSG_MOD(fco->common.extack,
566 "Unsupported match item");
567 return -ENOENT;
568 }
569
570 if (l3_proto)
571 *l3_proto = state.l3_proto;
572 return err;
573}
574
575static int sparx5_tc_flower_action_check(struct vcap_control *vctrl,
576 struct flow_cls_offload *fco,
577 struct vcap_admin *admin)
578{
579 struct flow_rule *rule = flow_cls_offload_flow_rule(fco);
580 struct flow_action_entry *actent, *last_actent = NULL;
581 struct flow_action *act = &rule->action;
582 u64 action_mask = 0;
583 int idx;
584
585 if (!flow_action_has_entries(act)) {
586 NL_SET_ERR_MSG_MOD(fco->common.extack, "No actions");
587 return -EINVAL;
588 }
589
590 if (!flow_action_basic_hw_stats_check(act, fco->common.extack))
591 return -EOPNOTSUPP;
592
593 flow_action_for_each(idx, actent, act) {
594 if (action_mask & BIT(actent->id)) {
595 NL_SET_ERR_MSG_MOD(fco->common.extack,
596 "More actions of the same type");
597 return -EINVAL;
598 }
599 action_mask |= BIT(actent->id);
600 last_actent = actent; /* Save last action for later check */
601 }
602
603 /* Check that last action is a goto */
604 if (last_actent->id != FLOW_ACTION_GOTO) {
605 NL_SET_ERR_MSG_MOD(fco->common.extack,
606 "Last action must be 'goto'");
607 return -EINVAL;
608 }
609
610 /* Check if the goto chain is in the next lookup */
611 if (!vcap_is_next_lookup(vctrl, fco->common.chain_index,
612 last_actent->chain_index)) {
613 NL_SET_ERR_MSG_MOD(fco->common.extack,
614 "Invalid goto chain");
615 return -EINVAL;
616 }
617
618 /* Catch unsupported combinations of actions */
619 if (action_mask & BIT(FLOW_ACTION_TRAP) &&
620 action_mask & BIT(FLOW_ACTION_ACCEPT)) {
621 NL_SET_ERR_MSG_MOD(fco->common.extack,
622 "Cannot combine pass and trap action");
623 return -EOPNOTSUPP;
624 }
625
626 return 0;
627}
628
629/* Add a rule counter action - only IS2 is considered for now */
630static int sparx5_tc_add_rule_counter(struct vcap_admin *admin,
631 struct vcap_rule *vrule)
632{
633 int err;
634
635 err = vcap_rule_mod_action_u32(vrule, VCAP_AF_CNT_ID, vrule->id);
636 if (err)
637 return err;
638
639 vcap_rule_set_counter_id(vrule, vrule->id);
640 return err;
641}
642
643/* Collect all port keysets and apply the first of them, possibly wildcarded */
644static int sparx5_tc_select_protocol_keyset(struct net_device *ndev,
645 struct vcap_rule *vrule,
646 struct vcap_admin *admin,
647 u16 l3_proto,
648 struct sparx5_multiple_rules *multi)
649{
650 struct sparx5_port *port = netdev_priv(ndev);
651 struct vcap_keyset_list portkeysetlist = {};
652 enum vcap_keyfield_set portkeysets[10] = {};
653 struct vcap_keyset_list matches = {};
654 enum vcap_keyfield_set keysets[10];
655 int idx, jdx, err = 0, count = 0;
656 struct sparx5_wildcard_rule *mru;
657 const struct vcap_set *kinfo;
658 struct vcap_control *vctrl;
659
660 vctrl = port->sparx5->vcap_ctrl;
661
662 /* Find the keysets that the rule can use */
663 matches.keysets = keysets;
664 matches.max = ARRAY_SIZE(keysets);
665 if (vcap_rule_find_keysets(vrule, &matches) == 0)
666 return -EINVAL;
667
668 /* Find the keysets that the port configuration supports */
669 portkeysetlist.max = ARRAY_SIZE(portkeysets);
670 portkeysetlist.keysets = portkeysets;
671 err = sparx5_vcap_get_port_keyset(ndev,
672 admin, vrule->vcap_chain_id,
673 l3_proto,
674 &portkeysetlist);
675 if (err)
676 return err;
677
678 /* Find the intersection of the two sets of keyset */
679 for (idx = 0; idx < portkeysetlist.cnt; ++idx) {
680 kinfo = vcap_keyfieldset(vctrl, admin->vtype,
681 portkeysetlist.keysets[idx]);
682 if (!kinfo)
683 continue;
684
685 /* Find a port keyset that matches the required keys
686 * If there are multiple keysets then compose a type id mask
687 */
688 for (jdx = 0; jdx < matches.cnt; ++jdx) {
689 if (portkeysetlist.keysets[idx] != matches.keysets[jdx])
690 continue;
691
692 mru = &multi->rule[kinfo->sw_per_item];
693 if (!mru->selected) {
694 mru->selected = true;
695 mru->keyset = portkeysetlist.keysets[idx];
696 mru->value = kinfo->type_id;
697 }
698 mru->value &= kinfo->type_id;
699 mru->mask |= kinfo->type_id;
700 ++count;
701 }
702 }
703 if (count == 0)
704 return -EPROTO;
705
706 if (l3_proto == ETH_P_ALL && count < portkeysetlist.cnt)
707 return -ENOENT;
708
709 for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) {
710 mru = &multi->rule[idx];
711 if (!mru->selected)
712 continue;
713
714 /* Align the mask to the combined value */
715 mru->mask ^= mru->value;
716 }
717
718 /* Set the chosen keyset on the rule and set a wildcarded type if there
719 * are more than one keyset
720 */
721 for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) {
722 mru = &multi->rule[idx];
723 if (!mru->selected)
724 continue;
725
726 vcap_set_rule_set_keyset(vrule, mru->keyset);
727 if (count > 1)
728 /* Some keysets do not have a type field */
729 vcap_rule_mod_key_u32(vrule, VCAP_KF_TYPE,
730 mru->value,
731 ~mru->mask);
732 mru->selected = false; /* mark as done */
733 break; /* Stop here and add more rules later */
734 }
735 return err;
736}
737
738static int sparx5_tc_add_rule_copy(struct vcap_control *vctrl,
739 struct flow_cls_offload *fco,
740 struct vcap_rule *erule,
741 struct vcap_admin *admin,
742 struct sparx5_wildcard_rule *rule)
743{
744 enum vcap_key_field keylist[] = {
745 VCAP_KF_IF_IGR_PORT_MASK,
746 VCAP_KF_IF_IGR_PORT_MASK_SEL,
747 VCAP_KF_IF_IGR_PORT_MASK_RNG,
748 VCAP_KF_LOOKUP_FIRST_IS,
749 VCAP_KF_TYPE,
750 };
751 struct vcap_rule *vrule;
752 int err;
753
754 /* Add an extra rule with a special user and the new keyset */
755 erule->user = VCAP_USER_TC_EXTRA;
756 vrule = vcap_copy_rule(erule);
757 if (IS_ERR(vrule))
758 return PTR_ERR(vrule);
759
760 /* Link the new rule to the existing rule with the cookie */
761 vrule->cookie = erule->cookie;
762 vcap_filter_rule_keys(vrule, keylist, ARRAY_SIZE(keylist), true);
763 err = vcap_set_rule_set_keyset(vrule, rule->keyset);
764 if (err) {
765 pr_err("%s:%d: could not set keyset %s in rule: %u\n",
766 __func__, __LINE__,
767 vcap_keyset_name(vctrl, rule->keyset),
768 vrule->id);
769 goto out;
770 }
771
772 /* Some keysets do not have a type field, so ignore return value */
773 vcap_rule_mod_key_u32(vrule, VCAP_KF_TYPE, rule->value, ~rule->mask);
774
775 err = vcap_set_rule_set_actionset(vrule, erule->actionset);
776 if (err)
777 goto out;
778
779 err = sparx5_tc_add_rule_counter(admin, vrule);
780 if (err)
781 goto out;
782
783 err = vcap_val_rule(vrule, ETH_P_ALL);
784 if (err) {
785 pr_err("%s:%d: could not validate rule: %u\n",
786 __func__, __LINE__, vrule->id);
787 vcap_set_tc_exterr(fco, vrule);
788 goto out;
789 }
790 err = vcap_add_rule(vrule);
791 if (err) {
792 pr_err("%s:%d: could not add rule: %u\n",
793 __func__, __LINE__, vrule->id);
794 goto out;
795 }
796out:
797 vcap_free_rule(vrule);
798 return err;
799}
800
801static int sparx5_tc_add_remaining_rules(struct vcap_control *vctrl,
802 struct flow_cls_offload *fco,
803 struct vcap_rule *erule,
804 struct vcap_admin *admin,
805 struct sparx5_multiple_rules *multi)
806{
807 int idx, err = 0;
808
809 for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) {
810 if (!multi->rule[idx].selected)
811 continue;
812
813 err = sparx5_tc_add_rule_copy(vctrl, fco, erule, admin,
814 &multi->rule[idx]);
815 if (err)
816 break;
817 }
818 return err;
819}
820
821static int sparx5_tc_flower_replace(struct net_device *ndev,
822 struct flow_cls_offload *fco,
823 struct vcap_admin *admin)
824{
825 struct sparx5_port *port = netdev_priv(ndev);
826 struct sparx5_multiple_rules multi = {};
827 struct flow_action_entry *act;
828 struct vcap_control *vctrl;
829 struct flow_rule *frule;
830 struct vcap_rule *vrule;
831 u16 l3_proto;
832 int err, idx;
833
834 vctrl = port->sparx5->vcap_ctrl;
835
836 err = sparx5_tc_flower_action_check(vctrl, fco, admin);
837 if (err)
838 return err;
839
840 vrule = vcap_alloc_rule(vctrl, ndev, fco->common.chain_index, VCAP_USER_TC,
841 fco->common.prio, 0);
842 if (IS_ERR(vrule))
843 return PTR_ERR(vrule);
844
845 vrule->cookie = fco->cookie;
846
847 l3_proto = ETH_P_ALL;
848 err = sparx5_tc_use_dissectors(fco, admin, vrule, &l3_proto);
849 if (err)
850 goto out;
851
852 err = sparx5_tc_add_rule_counter(admin, vrule);
853 if (err)
854 goto out;
855
856 frule = flow_cls_offload_flow_rule(fco);
857 flow_action_for_each(idx, act, &frule->action) {
858 switch (act->id) {
859 case FLOW_ACTION_TRAP:
860 err = vcap_rule_add_action_bit(vrule,
861 VCAP_AF_CPU_COPY_ENA,
862 VCAP_BIT_1);
863 if (err)
864 goto out;
865 err = vcap_rule_add_action_u32(vrule,
866 VCAP_AF_CPU_QUEUE_NUM, 0);
867 if (err)
868 goto out;
869 err = vcap_rule_add_action_u32(vrule, VCAP_AF_MASK_MODE,
870 SPX5_PMM_REPLACE_ALL);
871 if (err)
872 goto out;
873 /* For now the actionset is hardcoded */
874 err = vcap_set_rule_set_actionset(vrule,
875 VCAP_AFS_BASE_TYPE);
876 if (err)
877 goto out;
878 break;
879 case FLOW_ACTION_ACCEPT:
880 /* For now the actionset is hardcoded */
881 err = vcap_set_rule_set_actionset(vrule,
882 VCAP_AFS_BASE_TYPE);
883 if (err)
884 goto out;
885 break;
886 case FLOW_ACTION_GOTO:
887 /* Links between VCAPs will be added later */
888 break;
889 default:
890 NL_SET_ERR_MSG_MOD(fco->common.extack,
891 "Unsupported TC action");
892 err = -EOPNOTSUPP;
893 goto out;
894 }
895 }
896
897 err = sparx5_tc_select_protocol_keyset(ndev, vrule, admin, l3_proto,
898 &multi);
899 if (err) {
900 NL_SET_ERR_MSG_MOD(fco->common.extack,
901 "No matching port keyset for filter protocol and keys");
902 goto out;
903 }
904
905 /* provide the l3 protocol to guide the keyset selection */
906 err = vcap_val_rule(vrule, l3_proto);
907 if (err) {
908 vcap_set_tc_exterr(fco, vrule);
909 goto out;
910 }
911 err = vcap_add_rule(vrule);
912 if (err)
913 NL_SET_ERR_MSG_MOD(fco->common.extack,
914 "Could not add the filter");
915
916 if (l3_proto == ETH_P_ALL)
917 err = sparx5_tc_add_remaining_rules(vctrl, fco, vrule, admin,
918 &multi);
919
920out:
921 vcap_free_rule(vrule);
922 return err;
923}
924
925static int sparx5_tc_flower_destroy(struct net_device *ndev,
926 struct flow_cls_offload *fco,
927 struct vcap_admin *admin)
928{
929 struct sparx5_port *port = netdev_priv(ndev);
930 struct vcap_control *vctrl;
931 int err = -ENOENT, rule_id;
932
933 vctrl = port->sparx5->vcap_ctrl;
934 while (true) {
935 rule_id = vcap_lookup_rule_by_cookie(vctrl, fco->cookie);
936 if (rule_id <= 0)
937 break;
938 err = vcap_del_rule(vctrl, ndev, rule_id);
939 if (err) {
940 pr_err("%s:%d: could not delete rule %d\n",
941 __func__, __LINE__, rule_id);
942 break;
943 }
944 }
945 return err;
946}
947
948/* Collect packet counts from all rules with the same cookie */
949static int sparx5_tc_rule_counter_cb(void *arg, struct vcap_rule *rule)
950{
951 struct sparx5_tc_rule_pkt_cnt *rinfo = arg;
952 struct vcap_counter counter;
953 int err = 0;
954
955 if (rule->cookie == rinfo->cookie) {
956 err = vcap_rule_get_counter(rule, &counter);
957 if (err)
958 return err;
959 rinfo->pkts += counter.value;
960 /* Reset the rule counter */
961 counter.value = 0;
962 vcap_rule_set_counter(rule, &counter);
963 }
964 return err;
965}
966
967static int sparx5_tc_flower_stats(struct net_device *ndev,
968 struct flow_cls_offload *fco,
969 struct vcap_admin *admin)
970{
971 struct sparx5_port *port = netdev_priv(ndev);
972 struct sparx5_tc_rule_pkt_cnt rinfo = {};
973 struct vcap_control *vctrl;
974 ulong lastused = 0;
975 u64 drops = 0;
976 u32 pkts = 0;
977 int err;
978
979 rinfo.cookie = fco->cookie;
980 vctrl = port->sparx5->vcap_ctrl;
981 err = vcap_rule_iter(vctrl, sparx5_tc_rule_counter_cb, &rinfo);
982 if (err)
983 return err;
984 pkts = rinfo.pkts;
985 flow_stats_update(&fco->stats, 0x0, pkts, drops, lastused,
986 FLOW_ACTION_HW_STATS_IMMEDIATE);
987 return err;
988}
989
990int sparx5_tc_flower(struct net_device *ndev, struct flow_cls_offload *fco,
991 bool ingress)
992{
993 struct sparx5_port *port = netdev_priv(ndev);
994 struct vcap_control *vctrl;
995 struct vcap_admin *admin;
996 int err = -EINVAL;
997
998 /* Get vcap instance from the chain id */
999 vctrl = port->sparx5->vcap_ctrl;
1000 admin = vcap_find_admin(vctrl, fco->common.chain_index);
1001 if (!admin) {
1002 NL_SET_ERR_MSG_MOD(fco->common.extack, "Invalid chain");
1003 return err;
1004 }
1005
1006 switch (fco->command) {
1007 case FLOW_CLS_REPLACE:
1008 return sparx5_tc_flower_replace(ndev, fco, admin);
1009 case FLOW_CLS_DESTROY:
1010 return sparx5_tc_flower_destroy(ndev, fco, admin);
1011 case FLOW_CLS_STATS:
1012 return sparx5_tc_flower_stats(ndev, fco, admin);
1013 default:
1014 return -EOPNOTSUPP;
1015 }
1016}