Commit 784c3067 authored by Steen Hegelund's avatar Steen Hegelund Committed by David S. Miller

net: microchip: vcap api: Check chains when adding a tc flower filter

This changes the way the chain information verified when adding a new tc
flower filter.

When adding a flower filter it is now checked that the filter contains a
goto action to one of the IS2 VCAP lookups, except for the last lookup
which may omit this goto action.

It is also checked if you attempt to add multiple matchall filters to
enable the same VCAP lookup.  This will be rejected.
Signed-off-by: default avatarHoratiu Vultur <horatiu.vultur@microchip.com>
Signed-off-by: default avatarSteen Hegelund <steen.hegelund@microchip.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent cfd9e7b7
...@@ -82,8 +82,8 @@ static int lan966x_tc_flower_use_dissectors(struct flow_cls_offload *f, ...@@ -82,8 +82,8 @@ static int lan966x_tc_flower_use_dissectors(struct flow_cls_offload *f,
} }
static int lan966x_tc_flower_action_check(struct vcap_control *vctrl, static int lan966x_tc_flower_action_check(struct vcap_control *vctrl,
struct flow_cls_offload *fco, struct net_device *dev,
struct vcap_admin *admin) struct flow_cls_offload *fco)
{ {
struct flow_rule *rule = flow_cls_offload_flow_rule(fco); struct flow_rule *rule = flow_cls_offload_flow_rule(fco);
struct flow_action_entry *actent, *last_actent = NULL; struct flow_action_entry *actent, *last_actent = NULL;
...@@ -109,21 +109,23 @@ static int lan966x_tc_flower_action_check(struct vcap_control *vctrl, ...@@ -109,21 +109,23 @@ static int lan966x_tc_flower_action_check(struct vcap_control *vctrl,
last_actent = actent; /* Save last action for later check */ last_actent = actent; /* Save last action for later check */
} }
/* Check that last action is a goto */ /* Check that last action is a goto
if (last_actent->id != FLOW_ACTION_GOTO) { * The last chain/lookup does not need to have 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;
}
} else if (!vcap_is_last_chain(vctrl, fco->common.chain_index)) {
NL_SET_ERR_MSG_MOD(fco->common.extack, NL_SET_ERR_MSG_MOD(fco->common.extack,
"Last action must be 'goto'"); "Last action must be 'goto'");
return -EINVAL; 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 */ /* Catch unsupported combinations of actions */
if (action_mask & BIT(FLOW_ACTION_TRAP) && if (action_mask & BIT(FLOW_ACTION_TRAP) &&
action_mask & BIT(FLOW_ACTION_ACCEPT)) { action_mask & BIT(FLOW_ACTION_ACCEPT)) {
...@@ -145,8 +147,8 @@ static int lan966x_tc_flower_add(struct lan966x_port *port, ...@@ -145,8 +147,8 @@ static int lan966x_tc_flower_add(struct lan966x_port *port,
struct vcap_rule *vrule; struct vcap_rule *vrule;
int err, idx; int err, idx;
err = lan966x_tc_flower_action_check(port->lan966x->vcap_ctrl, f, err = lan966x_tc_flower_action_check(port->lan966x->vcap_ctrl,
admin); port->dev, f);
if (err) if (err)
return err; return err;
......
...@@ -573,8 +573,8 @@ static int sparx5_tc_use_dissectors(struct flow_cls_offload *fco, ...@@ -573,8 +573,8 @@ static int sparx5_tc_use_dissectors(struct flow_cls_offload *fco,
} }
static int sparx5_tc_flower_action_check(struct vcap_control *vctrl, static int sparx5_tc_flower_action_check(struct vcap_control *vctrl,
struct flow_cls_offload *fco, struct net_device *ndev,
struct vcap_admin *admin) struct flow_cls_offload *fco)
{ {
struct flow_rule *rule = flow_cls_offload_flow_rule(fco); struct flow_rule *rule = flow_cls_offload_flow_rule(fco);
struct flow_action_entry *actent, *last_actent = NULL; struct flow_action_entry *actent, *last_actent = NULL;
...@@ -600,21 +600,23 @@ static int sparx5_tc_flower_action_check(struct vcap_control *vctrl, ...@@ -600,21 +600,23 @@ static int sparx5_tc_flower_action_check(struct vcap_control *vctrl,
last_actent = actent; /* Save last action for later check */ last_actent = actent; /* Save last action for later check */
} }
/* Check that last action is a goto */ /* Check if last action is a goto
if (last_actent->id != FLOW_ACTION_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;
}
} else if (!vcap_is_last_chain(vctrl, fco->common.chain_index)) {
NL_SET_ERR_MSG_MOD(fco->common.extack, NL_SET_ERR_MSG_MOD(fco->common.extack,
"Last action must be 'goto'"); "Last action must be 'goto'");
return -EINVAL; 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 */ /* Catch unsupported combinations of actions */
if (action_mask & BIT(FLOW_ACTION_TRAP) && if (action_mask & BIT(FLOW_ACTION_TRAP) &&
action_mask & BIT(FLOW_ACTION_ACCEPT)) { action_mask & BIT(FLOW_ACTION_ACCEPT)) {
...@@ -833,7 +835,7 @@ static int sparx5_tc_flower_replace(struct net_device *ndev, ...@@ -833,7 +835,7 @@ static int sparx5_tc_flower_replace(struct net_device *ndev,
vctrl = port->sparx5->vcap_ctrl; vctrl = port->sparx5->vcap_ctrl;
err = sparx5_tc_flower_action_check(vctrl, fco, admin); err = sparx5_tc_flower_action_check(vctrl, ndev, fco);
if (err) if (err)
return err; return err;
......
...@@ -1553,39 +1553,31 @@ struct vcap_admin *vcap_find_admin(struct vcap_control *vctrl, int cid) ...@@ -1553,39 +1553,31 @@ struct vcap_admin *vcap_find_admin(struct vcap_control *vctrl, int cid)
} }
EXPORT_SYMBOL_GPL(vcap_find_admin); EXPORT_SYMBOL_GPL(vcap_find_admin);
/* Is the next chain id in the following lookup, possible in another VCAP */ /* Is the next chain id in one of the following lookups
bool vcap_is_next_lookup(struct vcap_control *vctrl, int cur_cid, int next_cid) * For now this does not support filters linked to other filters using
* keys and actions. That will be added later.
*/
bool vcap_is_next_lookup(struct vcap_control *vctrl, int src_cid, int dst_cid)
{ {
struct vcap_admin *admin, *next_admin; struct vcap_admin *admin;
int lookup, next_lookup; int next_cid;
/* The offset must be at least one lookup */ if (vcap_api_check(vctrl))
if (next_cid < cur_cid + VCAP_CID_LOOKUP_SIZE)
return false; return false;
if (vcap_api_check(vctrl)) /* The offset must be at least one lookup, round up */
next_cid = src_cid + VCAP_CID_LOOKUP_SIZE;
next_cid /= VCAP_CID_LOOKUP_SIZE;
next_cid *= VCAP_CID_LOOKUP_SIZE;
if (dst_cid < next_cid)
return false; return false;
admin = vcap_find_admin(vctrl, cur_cid); admin = vcap_find_admin(vctrl, dst_cid);
if (!admin) if (!admin)
return false; return false;
/* If no VCAP contains the next chain, the next chain must be beyond return true;
* 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); EXPORT_SYMBOL_GPL(vcap_is_next_lookup);
...@@ -2718,6 +2710,25 @@ int vcap_enable_lookups(struct vcap_control *vctrl, struct net_device *ndev, ...@@ -2718,6 +2710,25 @@ int vcap_enable_lookups(struct vcap_control *vctrl, struct net_device *ndev,
} }
EXPORT_SYMBOL_GPL(vcap_enable_lookups); EXPORT_SYMBOL_GPL(vcap_enable_lookups);
/* Is this chain id the last lookup of all VCAPs */
bool vcap_is_last_chain(struct vcap_control *vctrl, int cid)
{
struct vcap_admin *admin;
int lookup;
if (vcap_api_check(vctrl))
return false;
admin = vcap_find_admin(vctrl, cid);
if (!admin)
return false;
/* This must be the last lookup in this VCAP type */
lookup = vcap_chain_id_to_lookup(admin, cid);
return lookup == admin->lookups - 1;
}
EXPORT_SYMBOL_GPL(vcap_is_last_chain);
/* Set a rule counter id (for certain vcaps only) */ /* Set a rule counter id (for certain vcaps only) */
void vcap_rule_set_counter_id(struct vcap_rule *rule, u32 counter_id) void vcap_rule_set_counter_id(struct vcap_rule *rule, u32 counter_id)
{ {
......
...@@ -217,6 +217,8 @@ const struct vcap_field *vcap_lookup_keyfield(struct vcap_rule *rule, ...@@ -217,6 +217,8 @@ const struct vcap_field *vcap_lookup_keyfield(struct vcap_rule *rule,
int vcap_lookup_rule_by_cookie(struct vcap_control *vctrl, u64 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 */ /* 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); bool vcap_is_next_lookup(struct vcap_control *vctrl, int cur_cid, int next_cid);
/* Is this chain id the last lookup of all VCAPs */
bool vcap_is_last_chain(struct vcap_control *vctrl, int cid);
/* Provide all rules via a callback interface */ /* Provide all rules via a callback interface */
int vcap_rule_iter(struct vcap_control *vctrl, int vcap_rule_iter(struct vcap_control *vctrl,
int (*callback)(void *, struct vcap_rule *), void *arg); int (*callback)(void *, struct vcap_rule *), void *arg);
......
...@@ -1865,7 +1865,7 @@ static void vcap_api_next_lookup_basic_test(struct kunit *test) ...@@ -1865,7 +1865,7 @@ static void vcap_api_next_lookup_basic_test(struct kunit *test)
ret = vcap_is_next_lookup(&test_vctrl, 8300000, 8301000); ret = vcap_is_next_lookup(&test_vctrl, 8300000, 8301000);
KUNIT_EXPECT_EQ(test, false, ret); KUNIT_EXPECT_EQ(test, false, ret);
ret = vcap_is_next_lookup(&test_vctrl, 8300000, 8401000); ret = vcap_is_next_lookup(&test_vctrl, 8300000, 8401000);
KUNIT_EXPECT_EQ(test, true, ret); KUNIT_EXPECT_EQ(test, false, ret);
} }
static void vcap_api_next_lookup_advanced_test(struct kunit *test) static void vcap_api_next_lookup_advanced_test(struct kunit *test)
...@@ -1926,9 +1926,9 @@ static void vcap_api_next_lookup_advanced_test(struct kunit *test) ...@@ -1926,9 +1926,9 @@ static void vcap_api_next_lookup_advanced_test(struct kunit *test)
ret = vcap_is_next_lookup(&test_vctrl, 1100000, 1201000); ret = vcap_is_next_lookup(&test_vctrl, 1100000, 1201000);
KUNIT_EXPECT_EQ(test, true, ret); KUNIT_EXPECT_EQ(test, true, ret);
ret = vcap_is_next_lookup(&test_vctrl, 1100000, 1301000); ret = vcap_is_next_lookup(&test_vctrl, 1100000, 1301000);
KUNIT_EXPECT_EQ(test, false, ret); KUNIT_EXPECT_EQ(test, true, ret);
ret = vcap_is_next_lookup(&test_vctrl, 1100000, 8101000); ret = vcap_is_next_lookup(&test_vctrl, 1100000, 8101000);
KUNIT_EXPECT_EQ(test, false, ret); KUNIT_EXPECT_EQ(test, true, ret);
ret = vcap_is_next_lookup(&test_vctrl, 1300000, 1401000); ret = vcap_is_next_lookup(&test_vctrl, 1300000, 1401000);
KUNIT_EXPECT_EQ(test, true, ret); KUNIT_EXPECT_EQ(test, true, ret);
ret = vcap_is_next_lookup(&test_vctrl, 1400000, 1501000); ret = vcap_is_next_lookup(&test_vctrl, 1400000, 1501000);
...@@ -1944,7 +1944,7 @@ static void vcap_api_next_lookup_advanced_test(struct kunit *test) ...@@ -1944,7 +1944,7 @@ static void vcap_api_next_lookup_advanced_test(struct kunit *test)
ret = vcap_is_next_lookup(&test_vctrl, 8300000, 8301000); ret = vcap_is_next_lookup(&test_vctrl, 8300000, 8301000);
KUNIT_EXPECT_EQ(test, false, ret); KUNIT_EXPECT_EQ(test, false, ret);
ret = vcap_is_next_lookup(&test_vctrl, 8300000, 8401000); ret = vcap_is_next_lookup(&test_vctrl, 8300000, 8401000);
KUNIT_EXPECT_EQ(test, true, ret); KUNIT_EXPECT_EQ(test, false, ret);
} }
static void vcap_api_filter_unsupported_keys_test(struct kunit *test) static void vcap_api_filter_unsupported_keys_test(struct kunit *test)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment