net: microchip: sparx5: Adding TC goto action and action checking
Add support for a goto action and ensure that a HW offloaded TC flower filter has a valid goto action and that pass and trap actions are not both used in the same filter. Signed-off-by: Steen Hegelund <steen.hegelund@microchip.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
7de1dcadfa
commit
392d0ab048
@@ -464,6 +464,60 @@ static int sparx5_tc_use_dissectors(struct flow_cls_offload *fco,
|
||||
return err;
|
||||
}
|
||||
|
||||
static int sparx5_tc_flower_action_check(struct vcap_control *vctrl,
|
||||
struct flow_cls_offload *fco,
|
||||
struct vcap_admin *admin)
|
||||
{
|
||||
struct flow_rule *rule = flow_cls_offload_flow_rule(fco);
|
||||
struct flow_action_entry *actent, *last_actent = NULL;
|
||||
struct flow_action *act = &rule->action;
|
||||
u64 action_mask = 0;
|
||||
int idx;
|
||||
|
||||
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 that last action is a goto */
|
||||
if (last_actent->id != FLOW_ACTION_GOTO) {
|
||||
NL_SET_ERR_MSG_MOD(fco->common.extack,
|
||||
"Last action must be 'goto'");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check if the goto chain is in the next lookup */
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sparx5_tc_flower_replace(struct net_device *ndev,
|
||||
struct flow_cls_offload *fco,
|
||||
struct vcap_admin *admin)
|
||||
@@ -475,16 +529,12 @@ static int sparx5_tc_flower_replace(struct net_device *ndev,
|
||||
struct vcap_rule *vrule;
|
||||
int err, idx;
|
||||
|
||||
frule = flow_cls_offload_flow_rule(fco);
|
||||
if (!flow_action_has_entries(&frule->action)) {
|
||||
NL_SET_ERR_MSG_MOD(fco->common.extack, "No actions");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!flow_action_basic_hw_stats_check(&frule->action, fco->common.extack))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
vctrl = port->sparx5->vcap_ctrl;
|
||||
|
||||
err = sparx5_tc_flower_action_check(vctrl, fco, admin);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
vrule = vcap_alloc_rule(vctrl, ndev, fco->common.chain_index, VCAP_USER_TC,
|
||||
fco->common.prio, 0);
|
||||
if (IS_ERR(vrule))
|
||||
@@ -492,6 +542,7 @@ static int sparx5_tc_flower_replace(struct net_device *ndev,
|
||||
|
||||
vrule->cookie = fco->cookie;
|
||||
sparx5_tc_use_dissectors(fco, admin, vrule);
|
||||
frule = flow_cls_offload_flow_rule(fco);
|
||||
flow_action_for_each(idx, act, &frule->action) {
|
||||
switch (act->id) {
|
||||
case FLOW_ACTION_TRAP:
|
||||
@@ -521,6 +572,9 @@ static int sparx5_tc_flower_replace(struct net_device *ndev,
|
||||
if (err)
|
||||
goto out;
|
||||
break;
|
||||
case FLOW_ACTION_GOTO:
|
||||
/* Links between VCAPs will be added later */
|
||||
break;
|
||||
default:
|
||||
NL_SET_ERR_MSG_MOD(fco->common.extack,
|
||||
"Unsupported TC action");
|
||||
|
||||
@@ -677,6 +677,42 @@ struct vcap_admin *vcap_find_admin(struct vcap_control *vctrl, int cid)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vcap_find_admin);
|
||||
|
||||
/* Is the next chain id in the following lookup, possible in another VCAP */
|
||||
bool vcap_is_next_lookup(struct vcap_control *vctrl, int cur_cid, int next_cid)
|
||||
{
|
||||
struct vcap_admin *admin, *next_admin;
|
||||
int lookup, next_lookup;
|
||||
|
||||
/* The offset must be at least one lookup */
|
||||
if (next_cid < cur_cid + VCAP_CID_LOOKUP_SIZE)
|
||||
return false;
|
||||
|
||||
if (vcap_api_check(vctrl))
|
||||
return false;
|
||||
|
||||
admin = vcap_find_admin(vctrl, cur_cid);
|
||||
if (!admin)
|
||||
return false;
|
||||
|
||||
/* If no VCAP contains the next chain, the next chain must be beyond
|
||||
* the last chain in the current VCAP
|
||||
*/
|
||||
next_admin = vcap_find_admin(vctrl, next_cid);
|
||||
if (!next_admin)
|
||||
return next_cid > admin->last_cid;
|
||||
|
||||
lookup = vcap_chain_id_to_lookup(admin, cur_cid);
|
||||
next_lookup = vcap_chain_id_to_lookup(next_admin, next_cid);
|
||||
|
||||
/* Next lookup must be the following lookup */
|
||||
if (admin == next_admin || admin->vtype == next_admin->vtype)
|
||||
return next_lookup == lookup + 1;
|
||||
|
||||
/* Must be the first lookup in the next VCAP instance */
|
||||
return next_lookup == 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vcap_is_next_lookup);
|
||||
|
||||
/* Check if there is room for a new rule */
|
||||
static int vcap_rule_space(struct vcap_admin *admin, int size)
|
||||
{
|
||||
|
||||
@@ -193,6 +193,8 @@ const struct vcap_field *vcap_lookup_keyfield(struct vcap_rule *rule,
|
||||
enum vcap_key_field key);
|
||||
/* Find a rule id with a provided cookie */
|
||||
int vcap_lookup_rule_by_cookie(struct vcap_control *vctrl, u64 cookie);
|
||||
/* Is the next chain id in the following lookup, possible in another VCAP */
|
||||
bool vcap_is_next_lookup(struct vcap_control *vctrl, int cur_cid, int next_cid);
|
||||
|
||||
/* Copy to host byte order */
|
||||
void vcap_netbytes_copy(u8 *dst, u8 *src, int count);
|
||||
|
||||
Reference in New Issue
Block a user