@@ -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,
- struct flow_cls_offload *fco,
- struct vcap_admin *admin)
+ struct net_device *dev,
+ struct flow_cls_offload *fco)
{
struct flow_rule *rule = flow_cls_offload_flow_rule(fco);
struct flow_action_entry *actent, *last_actent = NULL;
@@ -109,21 +109,23 @@ static int lan966x_tc_flower_action_check(struct vcap_control *vctrl,
last_actent = actent; /* Save last action for later check */
}
- /* Check that last action is a goto */
- if (last_actent->id != FLOW_ACTION_GOTO) {
+ /* Check that last action is a 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,
"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)) {
@@ -145,8 +147,8 @@ static int lan966x_tc_flower_add(struct lan966x_port *port,
struct vcap_rule *vrule;
int err, idx;
- err = lan966x_tc_flower_action_check(port->lan966x->vcap_ctrl, f,
- admin);
+ err = lan966x_tc_flower_action_check(port->lan966x->vcap_ctrl,
+ port->dev, f);
if (err)
return err;
@@ -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,
- struct flow_cls_offload *fco,
- struct vcap_admin *admin)
+ struct net_device *ndev,
+ struct flow_cls_offload *fco)
{
struct flow_rule *rule = flow_cls_offload_flow_rule(fco);
struct flow_action_entry *actent, *last_actent = NULL;
@@ -600,21 +600,23 @@ static int sparx5_tc_flower_action_check(struct vcap_control *vctrl,
last_actent = actent; /* Save last action for later check */
}
- /* Check that last action is a goto */
- if (last_actent->id != FLOW_ACTION_GOTO) {
+ /* 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;
+ }
+ } else if (!vcap_is_last_chain(vctrl, fco->common.chain_index)) {
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)) {
@@ -833,7 +835,7 @@ static int sparx5_tc_flower_replace(struct net_device *ndev,
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)
return err;
@@ -1553,39 +1553,31 @@ 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)
+/* Is the next chain id in one of the following lookups
+ * 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;
- int lookup, next_lookup;
+ struct vcap_admin *admin;
+ int next_cid;
- /* The offset must be at least one lookup */
- if (next_cid < cur_cid + VCAP_CID_LOOKUP_SIZE)
+ if (vcap_api_check(vctrl))
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;
- admin = vcap_find_admin(vctrl, cur_cid);
+ admin = vcap_find_admin(vctrl, dst_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;
+ return true;
}
EXPORT_SYMBOL_GPL(vcap_is_next_lookup);
@@ -2718,6 +2710,25 @@ int vcap_enable_lookups(struct vcap_control *vctrl, struct net_device *ndev,
}
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) */
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,
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);
+/* 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 */
int vcap_rule_iter(struct vcap_control *vctrl,
int (*callback)(void *, struct vcap_rule *), void *arg);
@@ -1865,7 +1865,7 @@ static void vcap_api_next_lookup_basic_test(struct kunit *test)
ret = vcap_is_next_lookup(&test_vctrl, 8300000, 8301000);
KUNIT_EXPECT_EQ(test, false, ret);
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)
@@ -1926,9 +1926,9 @@ static void vcap_api_next_lookup_advanced_test(struct kunit *test)
ret = vcap_is_next_lookup(&test_vctrl, 1100000, 1201000);
KUNIT_EXPECT_EQ(test, true, ret);
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);
- KUNIT_EXPECT_EQ(test, false, ret);
+ KUNIT_EXPECT_EQ(test, true, ret);
ret = vcap_is_next_lookup(&test_vctrl, 1300000, 1401000);
KUNIT_EXPECT_EQ(test, true, ret);
ret = vcap_is_next_lookup(&test_vctrl, 1400000, 1501000);
@@ -1944,7 +1944,7 @@ static void vcap_api_next_lookup_advanced_test(struct kunit *test)
ret = vcap_is_next_lookup(&test_vctrl, 8300000, 8301000);
KUNIT_EXPECT_EQ(test, false, ret);
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)