struct sparx5_tc_flower_template { struct list_head list; /* for insertion in the list of templates */ int cid; /* chain id */ enum vcap_keyfield_set orig; /* keyset used before the template */ enum vcap_keyfield_set keyset; /* new keyset used by template */
u16 l3_proto; /* protocol specified in the template */
};
staticint
sparx5_tc_flower_handler_cvlan_usage(struct vcap_tc_flower_parse_usage *st)
{ if (st->admin->vtype != VCAP_TYPE_IS0) {
NL_SET_ERR_MSG_MOD(st->fco->common.extack, "cvlan not supported in this VCAP"); return -EINVAL;
}
if (!flow_action_has_entries(act)) {
NL_SET_ERR_MSG_MOD(fco->common.extack, "No actions"); return -EINVAL;
}
if (!flow_action_basic_hw_stats_check(act, fco->common.extack)) return -EOPNOTSUPP;
flow_action_for_each(idx, actent, act) { if (action_mask & BIT(actent->id)) {
NL_SET_ERR_MSG_MOD(fco->common.extack, "More actions of the same type"); return -EINVAL;
}
action_mask |= BIT(actent->id);
last_actent = actent; /* Save last action for later check */
}
/* Check if last action is a goto * The last chain/lookup does not need to have a goto action
*/ if (last_actent->id == FLOW_ACTION_GOTO) { /* Check if the destination chain is in one of the VCAPs */ if (!vcap_is_next_lookup(vctrl, fco->common.chain_index,
last_actent->chain_index)) {
NL_SET_ERR_MSG_MOD(fco->common.extack, "Invalid goto chain"); return -EINVAL;
}
} elseif (!vcap_is_last_chain(vctrl, fco->common.chain_index,
ingress)) {
NL_SET_ERR_MSG_MOD(fco->common.extack, "Last action must be 'goto'"); return -EINVAL;
}
/* Catch unsupported combinations of actions */ if (action_mask & BIT(FLOW_ACTION_TRAP) &&
action_mask & BIT(FLOW_ACTION_ACCEPT)) {
NL_SET_ERR_MSG_MOD(fco->common.extack, "Cannot combine pass and trap action"); return -EOPNOTSUPP;
}
if (action_mask & BIT(FLOW_ACTION_VLAN_PUSH) &&
action_mask & BIT(FLOW_ACTION_VLAN_POP)) {
NL_SET_ERR_MSG_MOD(fco->common.extack, "Cannot combine vlan push and pop action"); return -EOPNOTSUPP;
}
if (action_mask & BIT(FLOW_ACTION_VLAN_PUSH) &&
action_mask & BIT(FLOW_ACTION_VLAN_MANGLE)) {
NL_SET_ERR_MSG_MOD(fco->common.extack, "Cannot combine vlan push and modify action"); return -EOPNOTSUPP;
}
if (action_mask & BIT(FLOW_ACTION_VLAN_POP) &&
action_mask & BIT(FLOW_ACTION_VLAN_MANGLE)) {
NL_SET_ERR_MSG_MOD(fco->common.extack, "Cannot combine vlan pop and modify action"); return -EOPNOTSUPP;
}
return 0;
}
/* Add a rule counter action */ staticint sparx5_tc_add_rule_counter(struct vcap_admin *admin, struct vcap_rule *vrule)
{ int err;
switch (admin->vtype) { case VCAP_TYPE_IS0: break; case VCAP_TYPE_ES0:
err = vcap_rule_mod_action_u32(vrule, VCAP_AF_ESDX,
vrule->id); if (err) return err;
vcap_rule_set_counter_id(vrule, vrule->id); break; case VCAP_TYPE_IS2: case VCAP_TYPE_ES2:
err = vcap_rule_mod_action_u32(vrule, VCAP_AF_CNT_ID,
vrule->id); if (err) return err;
vcap_rule_set_counter_id(vrule, vrule->id); break; default:
pr_err("%s:%d: vcap type: %d not supported\n",
__func__, __LINE__, admin->vtype); break;
} return 0;
}
/* Find the keysets that the rule can use */
matches.keysets = keysets;
matches.max = ARRAY_SIZE(keysets); if (!vcap_rule_find_keysets(vrule, &matches)) return -EINVAL;
/* Find the keysets that the port configuration supports */
portkeysetlist.max = ARRAY_SIZE(portkeysets);
portkeysetlist.keysets = portkeysets;
err = sparx5_vcap_get_port_keyset(ndev,
admin, vrule->vcap_chain_id,
l3_proto,
&portkeysetlist); if (err) return err;
/* Find the intersection of the two sets of keyset */ for (idx = 0; idx < portkeysetlist.cnt; ++idx) {
kinfo = vcap_keyfieldset(vctrl, admin->vtype,
portkeysetlist.keysets[idx]); if (!kinfo) continue;
/* Find a port keyset that matches the required keys * If there are multiple keysets then compose a type id mask
*/ for (jdx = 0; jdx < matches.cnt; ++jdx) { if (portkeysetlist.keysets[idx] != matches.keysets[jdx]) continue;
if (l3_proto == ETH_P_ALL && count < portkeysetlist.cnt) return -ENOENT;
for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) {
mru = &multi->rule[idx]; if (!mru->selected) continue;
/* Align the mask to the combined value */
mru->mask ^= mru->value;
}
/* Set the chosen keyset on the rule and set a wildcarded type if there * are more than one keyset
*/ for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) {
mru = &multi->rule[idx]; if (!mru->selected) continue;
vcap_set_rule_set_keyset(vrule, mru->keyset); if (count > 1) /* Some keysets do not have a type field */
vcap_rule_mod_key_u32(vrule, VCAP_KF_TYPE,
mru->value,
~mru->mask);
mru->selected = false; /* mark as done */ break; /* Stop here and add more rules later */
} return err;
}
/* Add an extra rule with a special user and the new keyset */
erule->user = VCAP_USER_TC_EXTRA;
vrule = vcap_copy_rule(erule); if (IS_ERR(vrule)) return PTR_ERR(vrule);
/* Link the new rule to the existing rule with the cookie */
vrule->cookie = erule->cookie;
vcap_filter_rule_keys(vrule, keylist, ARRAY_SIZE(keylist), true);
err = vcap_set_rule_set_keyset(vrule, rule->keyset); if (err) {
pr_err("%s:%d: could not set keyset %s in rule: %u\n",
__func__, __LINE__,
vcap_keyset_name(vctrl, rule->keyset),
vrule->id); goto out;
}
/* Some keysets do not have a type field, so ignore return value */
vcap_rule_mod_key_u32(vrule, VCAP_KF_TYPE, rule->value, ~rule->mask);
err = vcap_set_rule_set_actionset(vrule, erule->actionset); if (err) goto out;
err = sparx5_tc_add_rule_counter(admin, vrule); if (err) goto out;
err = vcap_val_rule(vrule, ETH_P_ALL); if (err) {
pr_err("%s:%d: could not validate rule: %u\n",
__func__, __LINE__, vrule->id);
vcap_set_tc_exterr(fco, vrule); goto out;
}
err = vcap_add_rule(vrule); if (err) {
pr_err("%s:%d: could not add rule: %u\n",
__func__, __LINE__, vrule->id); goto out;
}
out:
vcap_free_rule(vrule); return err;
}
/* Add the actionset that is the default for the VCAP type */ staticint sparx5_tc_set_actionset(struct vcap_admin *admin, struct vcap_rule *vrule)
{ enum vcap_actionfield_set aset; int err = 0;
switch (admin->vtype) { case VCAP_TYPE_IS0:
aset = VCAP_AFS_CLASSIFICATION; break; case VCAP_TYPE_IS2:
aset = VCAP_AFS_BASE_TYPE; break; case VCAP_TYPE_ES0:
aset = VCAP_AFS_ES0; break; case VCAP_TYPE_ES2:
aset = VCAP_AFS_BASE_TYPE; break; default:
pr_err("%s:%d: %s\n", __func__, __LINE__, "Invalid VCAP type"); return -EINVAL;
} /* Do not overwrite any current actionset */ if (vrule->actionset == VCAP_AFS_NO_VALUE)
err = vcap_set_rule_set_actionset(vrule, aset); return err;
}
/* Add the VCAP key to match on for a rule target value */ staticint sparx5_tc_add_rule_link_target(struct vcap_admin *admin, struct vcap_rule *vrule, int target_cid)
{ int link_val = target_cid % VCAP_CID_LOOKUP_SIZE; int err;
if (!link_val) return 0;
switch (admin->vtype) { case VCAP_TYPE_IS0: /* Add NXT_IDX key for chaining rules between IS0 instances */
err = vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_GEN_IDX_SEL,
1, /* enable */
~0); if (err) return err; return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_GEN_IDX,
link_val, /* target */
~0); case VCAP_TYPE_IS2: /* Add PAG key for chaining rules from IS0 */ return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_PAG,
link_val, /* target */
~0); case VCAP_TYPE_ES0: case VCAP_TYPE_ES2: /* Add ISDX key for chaining rules from IS0 */ return vcap_rule_add_key_u32(vrule, VCAP_KF_ISDX_CLS, link_val,
~0); default: break;
} return 0;
}
/* Add the VCAP action that adds a target value to a rule */ staticint sparx5_tc_add_rule_link(struct vcap_control *vctrl, struct vcap_admin *admin, struct vcap_rule *vrule, int from_cid, int to_cid)
{ struct vcap_admin *to_admin = vcap_find_admin(vctrl, to_cid); int diff, err = 0;
/* rate is now in kbit */ if (pol->rate > DIV_ROUND_UP(SPX5_SDLB_GROUP_RATE_MAX, 1000)) {
NL_SET_ERR_MSG_MOD(extack, "Maximum rate exceeded"); return -EINVAL;
}
if (act->police.exceed.act_id != FLOW_ACTION_DROP) {
NL_SET_ERR_MSG_MOD(extack, "Offload not supported when exceed action is not drop"); return -EOPNOTSUPP;
}
if (act->police.notexceed.act_id != FLOW_ACTION_PIPE &&
act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
NL_SET_ERR_MSG_MOD(extack, "Offload not supported when conform action is not pipe or ok"); return -EOPNOTSUPP;
}
/* Must always have a stream gate - max sdu (filter option) is evaluated * after frames have passed the gate, so in case of only a policer, we * allocate a stream gate that is always open.
*/ if (sg_idx < 0) { /* Always-open stream gate is always the last */
sg_idx = sparx5_pool_idx_to_id(sparx5->data->consts->n_gates -
1);
sg->ipv = 0; /* Disabled */
sg->cycletime = SPX5_PSFP_SG_CYCLE_TIME_DEFAULT;
sg->num_entries = 1;
sg->gate_state = 1; /* Open */
sg->gate_enabled = 1;
sg->gce[0].gate_state = 1;
sg->gce[0].interval = SPX5_PSFP_SG_CYCLE_TIME_DEFAULT;
sg->gce[0].ipv = 0;
sg->gce[0].maxoctets = 0; /* Disabled */
}
ret = sparx5_psfp_sg_add(sparx5, sg_idx, sg, &psfp_sgid); if (ret < 0) return ret;
if (pol_idx >= 0) { /* Add new flow-meter */
ret = sparx5_psfp_fm_add(sparx5, pol_idx, fm, &psfp_fmid); if (ret < 0) return ret;
}
switch (admin->vtype) { case VCAP_TYPE_ES0: break; default:
NL_SET_ERR_MSG_MOD(fco->common.extack, "VLAN pop action not supported in this VCAP"); return -EOPNOTSUPP;
}
switch (admin->vtype) { case VCAP_TYPE_ES0: break; default:
NL_SET_ERR_MSG_MOD(fco->common.extack, "VLAN push action not supported in this VCAP"); return -EOPNOTSUPP;
}
if (tpid == ETH_P_8021AD) {
NL_SET_ERR_MSG_MOD(fco->common.extack, "Cannot push on double tagged frames"); return -EOPNOTSUPP;
}
if (admin->vtype != VCAP_TYPE_IS0 && admin->vtype != VCAP_TYPE_IS2) {
NL_SET_ERR_MSG_MOD(fco->common.extack, "Mirror action not supported in this VCAP"); return -EOPNOTSUPP;
}
err = vcap_rule_add_action_u32(vrule, VCAP_AF_MASK_MODE,
SPX5_PMM_OR_DSTMASK); if (err) return err;
if (admin->vtype != VCAP_TYPE_IS0 && admin->vtype != VCAP_TYPE_IS2) {
NL_SET_ERR_MSG_MOD(fco->common.extack, "Redirect action not supported in this VCAP"); return -EOPNOTSUPP;
}
err = vcap_rule_add_action_u32(vrule, VCAP_AF_MASK_MODE,
SPX5_PMM_REPLACE_ALL); if (err) return err;
if (!sparx5_tc_flower_use_template(ndev, fco, admin, vrule)) {
err = sparx5_tc_select_protocol_keyset(ndev, vrule, admin,
state.l3_proto, &multi); if (err) {
NL_SET_ERR_MSG_MOD(fco->common.extack, "No matching port keyset for filter protocol and keys"); goto out;
}
}
/* provide the l3 protocol to guide the keyset selection */
err = vcap_val_rule(vrule, state.l3_proto); if (err) {
vcap_set_tc_exterr(fco, vrule); goto out;
}
err = vcap_add_rule(vrule); if (err)
NL_SET_ERR_MSG_MOD(fco->common.extack, "Could not add the filter");
/* Check if VCAP_AF_ISDX_VAL action is set for this rule - and if * it is used for stream and/or flow-meter classification.
*/
afield = vcap_find_actionfield(vrule, VCAP_AF_ISDX_VAL); if (!afield) return;
vctrl = port->sparx5->vcap_ctrl; while (true) {
rule_id = vcap_lookup_rule_by_cookie(vctrl, fco->cookie); if (rule_id <= 0) break; if (count == 0) { /* Resources are attached to the first rule of * a set of rules. Only works if the rules are * in the correct order.
*/
err = sparx5_tc_free_rule_resources(ndev, vctrl,
rule_id); if (err)
pr_err("%s:%d: could not free resources %d\n",
__func__, __LINE__, rule_id);
}
err = vcap_del_rule(vctrl, ndev, rule_id); if (err) {
pr_err("%s:%d: could not delete rule %d\n",
__func__, __LINE__, rule_id); break;
}
} return err;
}
/* Find the keysets that the rule can use */
kslist.keysets = keysets;
kslist.max = ARRAY_SIZE(keysets); if (!vcap_rule_find_keysets(vrule, &kslist)) {
pr_err("%s:%d: %s\n", __func__, __LINE__, "Could not find a suitable keyset");
err = -ENOENT; goto out;
}
/* Rules using the template are removed by the tc framework */
list_for_each_entry_safe(ftp, tmp, &port->tc_templates, list) { if (ftp->cid != fco->common.chain_index) continue;
/* Get vcap instance from the chain id */
vctrl = port->sparx5->vcap_ctrl;
admin = vcap_find_admin(vctrl, fco->common.chain_index); if (!admin) {
NL_SET_ERR_MSG_MOD(fco->common.extack, "Invalid chain"); return err;
}
switch (fco->command) { case FLOW_CLS_REPLACE: return sparx5_tc_flower_replace(ndev, fco, admin, ingress); case FLOW_CLS_DESTROY: return sparx5_tc_flower_destroy(ndev, fco, admin); case FLOW_CLS_STATS: return sparx5_tc_flower_stats(ndev, fco, admin); case FLOW_CLS_TMPLT_CREATE: return sparx5_tc_flower_template_create(ndev, fco, admin); case FLOW_CLS_TMPLT_DESTROY: return sparx5_tc_flower_template_destroy(ndev, fco, admin); default: return -EOPNOTSUPP;
}
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.7 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.