1575 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/* Microchip VCAP API3 *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 39/* SparX-5 VCAP fragment types:40 * 0 = no fragment, 1 = initial fragment,41 * 2 = suspicious fragment, 3 = valid follow-up fragment42 */43enum { /* 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 */52static 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 60static int61sparx5_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 85static int86sparx5_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 154out:155 NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_proto parse error");156 return err;157}158 159static int160sparx5_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 210static int211sparx5_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 222static int223sparx5_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 244static 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 258static 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 283static 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 goto313 * The last chain/lookup does not need to have a goto action314 */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 */363static 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 */395static 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 keys437 * If there are multiple keysets then compose a type id mask438 */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 there470 * are more than one keyset471 */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 489static 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 }547out:548 vcap_free_rule(vrule);549 return err;550}551 552static 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 */573static 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 */603static 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 */641static 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 }698out:699 return err;700}701 702static 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 745static 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 774static 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 evaluated784 * after frames have passed the gate, so in case of only a policer, we785 * 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 */835static 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 879static 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 910static 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 980static 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 1030static 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 1040static 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 1064static 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 */1089static 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 1136static 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 1155static 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 1316out:1317 vcap_free_rule(vrule);1318 return err;1319}1320 1321static 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 if1328 * 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 1358static 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 1377static 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 of1392 * a set of rules. Only works if the rules are1393 * 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 1411static 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 1430static 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 1513out:1514 vcap_free_rule(vrule);1515err_rule:1516 kfree(ftp);1517 return err;1518}1519 1520static 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 1544int 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