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