2023-01-05 08:42:54

by Steen Hegelund

[permalink] [raw]
Subject: [PATCH net-next 0/8] Add support for two classes of VCAP rules

This adds support for two classes of VCAP rules:

- Permanent rules (added e.g. for PTP support)
- TC user rules (added by the TC userspace tool)

For this to work the VCAP Loopups must be enabled from boot, so that the
"internal" clients like PTP can add rules that are always active.

When the TC tool add a flower filter the VCAP rule corresponding to this
filter will be disabled (kept in memory) until a TC matchall filter creates
a link from chain 0 to the chain (lookup) where the flower filter was
added.

When the flower filter is enabled it will be written to the appropriate
VCAP lookup and become active in HW.

Likewise the flower filter will be disabled if there is no link from chain
0 to the chain of the filter (lookup), and when that happens the
corresponding VCAP rule will be read from the VCAP instance and stored in
memory until it is deleted or enabled again.

Steen Hegelund (8):
net: microchip: vcap api: Erase VCAP cache before encoding rule
net: microchip: sparx5: Reset VCAP counter for new rules
net: microchip: vcap api: Always enable VCAP lookups
net: microchip: vcap api: Convert multi-word keys/actions when
encoding
net: microchip: vcap api: Use src and dst chain id to chain VCAP
lookups
net: microchip: vcap api: Check chains when adding a tc flower filter
net: microchip: vcap api: Add a storage state to a VCAP rule
net: microchip: vcap api: Enable/Disable rules via chains in VCAP HW

.../ethernet/microchip/lan966x/lan966x_goto.c | 10 +-
.../ethernet/microchip/lan966x/lan966x_main.h | 3 +-
.../microchip/lan966x/lan966x_tc_flower.c | 30 +-
.../microchip/lan966x/lan966x_tc_matchall.c | 16 +-
.../microchip/lan966x/lan966x_vcap_impl.c | 24 +-
.../microchip/sparx5/sparx5_tc_flower.c | 28 +-
.../microchip/sparx5/sparx5_tc_matchall.c | 16 +-
.../microchip/sparx5/sparx5_vcap_debugfs.c | 2 +-
.../microchip/sparx5/sparx5_vcap_impl.c | 29 +-
.../net/ethernet/microchip/vcap/vcap_api.c | 752 +++++++++++++-----
.../net/ethernet/microchip/vcap/vcap_api.h | 5 -
.../ethernet/microchip/vcap/vcap_api_client.h | 8 +-
.../microchip/vcap/vcap_api_debugfs.c | 57 +-
.../microchip/vcap/vcap_api_debugfs_kunit.c | 10 +-
.../ethernet/microchip/vcap/vcap_api_kunit.c | 32 +-
.../microchip/vcap/vcap_api_private.h | 12 +-
16 files changed, 685 insertions(+), 349 deletions(-)

--
2.39.0


2023-01-05 08:43:23

by Steen Hegelund

[permalink] [raw]
Subject: [PATCH net-next 5/8] net: microchip: vcap api: Use src and dst chain id to chain VCAP lookups

This adds both the source and destination chain id to the information kept
for enabled port lookups.
This allows enabling and disabling a chain of lookups by walking the chain
information for a port.

This changes the way that VCAP lookups are enabled from userspace: instead
of one matchall rule that enables all the 4 Sparx5 IS2 lookups, you need a
matchall rule per lookup.

In practice that is done by adding one matchall rule in chain 0 to goto IS2
Lookup 0, and then for each lookup you add a rule per lookup (low priority)
that does a goto to the next lookup chain.

Examples:

If you want IS2 Lookup 0 to be enabled you add the same matchall filter as
before:

tc filter add dev eth12 ingress chain 0 prio 1000 handle 1000 matchall \
skip_sw action goto chain 8000000

If you also want to enable lookup 1 to 3 in IS2 and chain them you need
to add the following matchall filters:

tc filter add dev eth12 ingress chain 8000000 prio 1000 handle 1000 \
matchall skip_sw action goto chain 8100000

tc filter add dev eth12 ingress chain 8100000 prio 1000 handle 1000 \
matchall skip_sw action goto chain 8200000

tc filter add dev eth12 ingress chain 8200000 prio 1000 handle 1000 \
matchall skip_sw action goto chain 8300000

Fixes: 4426b78c626d ("net: lan966x: Add port keyset config and callback interface")
Signed-off-by: Horatiu Vultur <[email protected]>
Signed-off-by: Steen Hegelund <[email protected]>
---
.../ethernet/microchip/lan966x/lan966x_goto.c | 10 +-
.../ethernet/microchip/lan966x/lan966x_main.h | 3 +-
.../microchip/lan966x/lan966x_tc_matchall.c | 16 +--
.../microchip/sparx5/sparx5_tc_matchall.c | 16 +--
.../net/ethernet/microchip/vcap/vcap_api.c | 126 ++++++++++--------
.../ethernet/microchip/vcap/vcap_api_client.h | 5 +-
6 files changed, 92 insertions(+), 84 deletions(-)

diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_goto.c b/drivers/net/ethernet/microchip/lan966x/lan966x_goto.c
index bf0cfe24a8fc..9b18156eea1a 100644
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_goto.c
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_goto.c
@@ -4,7 +4,7 @@
#include "vcap_api_client.h"

int lan966x_goto_port_add(struct lan966x_port *port,
- struct flow_action_entry *act,
+ int from_cid, int to_cid,
unsigned long goto_id,
struct netlink_ext_ack *extack)
{
@@ -12,7 +12,7 @@ int lan966x_goto_port_add(struct lan966x_port *port,
int err;

err = vcap_enable_lookups(lan966x->vcap_ctrl, port->dev,
- act->chain_index, goto_id,
+ from_cid, to_cid, goto_id,
true);
if (err == -EFAULT) {
NL_SET_ERR_MSG_MOD(extack, "Unsupported goto chain");
@@ -29,8 +29,6 @@ int lan966x_goto_port_add(struct lan966x_port *port,
return err;
}

- port->tc.goto_id = goto_id;
-
return 0;
}

@@ -41,14 +39,12 @@ int lan966x_goto_port_del(struct lan966x_port *port,
struct lan966x *lan966x = port->lan966x;
int err;

- err = vcap_enable_lookups(lan966x->vcap_ctrl, port->dev, 0,
+ err = vcap_enable_lookups(lan966x->vcap_ctrl, port->dev, 0, 0,
goto_id, false);
if (err) {
NL_SET_ERR_MSG_MOD(extack, "Could not disable VCAP lookups");
return err;
}

- port->tc.goto_id = 0;
-
return 0;
}
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h
index 3491f1961835..0106f9487cbe 100644
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h
@@ -332,7 +332,6 @@ struct lan966x_port_tc {
unsigned long police_id;
unsigned long ingress_mirror_id;
unsigned long egress_mirror_id;
- unsigned long goto_id;
struct flow_stats police_stat;
struct flow_stats mirror_stat;
};
@@ -607,7 +606,7 @@ int lan966x_tc_flower(struct lan966x_port *port,
struct flow_cls_offload *f);

int lan966x_goto_port_add(struct lan966x_port *port,
- struct flow_action_entry *act,
+ int from_cid, int to_cid,
unsigned long goto_id,
struct netlink_ext_ack *extack);
int lan966x_goto_port_del(struct lan966x_port *port,
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_tc_matchall.c b/drivers/net/ethernet/microchip/lan966x/lan966x_tc_matchall.c
index a539abaad9b6..20627323d656 100644
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_tc_matchall.c
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_tc_matchall.c
@@ -24,7 +24,8 @@ static int lan966x_tc_matchall_add(struct lan966x_port *port,
return lan966x_mirror_port_add(port, act, f->cookie,
ingress, f->common.extack);
case FLOW_ACTION_GOTO:
- return lan966x_goto_port_add(port, act, f->cookie,
+ return lan966x_goto_port_add(port, f->common.chain_index,
+ act->chain_index, f->cookie,
f->common.extack);
default:
NL_SET_ERR_MSG_MOD(f->common.extack,
@@ -46,13 +47,8 @@ static int lan966x_tc_matchall_del(struct lan966x_port *port,
f->cookie == port->tc.egress_mirror_id) {
return lan966x_mirror_port_del(port, ingress,
f->common.extack);
- } else if (f->cookie == port->tc.goto_id) {
- return lan966x_goto_port_del(port, f->cookie,
- f->common.extack);
} else {
- NL_SET_ERR_MSG_MOD(f->common.extack,
- "Unsupported action");
- return -EOPNOTSUPP;
+ return lan966x_goto_port_del(port, f->cookie, f->common.extack);
}

return 0;
@@ -80,12 +76,6 @@ int lan966x_tc_matchall(struct lan966x_port *port,
struct tc_cls_matchall_offload *f,
bool ingress)
{
- if (!tc_cls_can_offload_and_chain0(port->dev, &f->common)) {
- NL_SET_ERR_MSG_MOD(f->common.extack,
- "Only chain zero is supported");
- return -EOPNOTSUPP;
- }
-
switch (f->command) {
case TC_CLSMATCHALL_REPLACE:
return lan966x_tc_matchall_add(port, f, ingress);
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_tc_matchall.c b/drivers/net/ethernet/microchip/sparx5/sparx5_tc_matchall.c
index 30dd61e5d150..d88a93f22606 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_tc_matchall.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_tc_matchall.c
@@ -31,6 +31,7 @@ static int sparx5_tc_matchall_replace(struct net_device *ndev,
switch (action->id) {
case FLOW_ACTION_GOTO:
err = vcap_enable_lookups(sparx5->vcap_ctrl, ndev,
+ tmo->common.chain_index,
action->chain_index, tmo->cookie,
true);
if (err == -EFAULT) {
@@ -43,6 +44,11 @@ static int sparx5_tc_matchall_replace(struct net_device *ndev,
"VCAP already enabled");
return -EOPNOTSUPP;
}
+ if (err == -EADDRNOTAVAIL) {
+ NL_SET_ERR_MSG_MOD(tmo->common.extack,
+ "Already matching this chain");
+ return -EOPNOTSUPP;
+ }
if (err) {
NL_SET_ERR_MSG_MOD(tmo->common.extack,
"Could not enable VCAP lookups");
@@ -66,8 +72,8 @@ static int sparx5_tc_matchall_destroy(struct net_device *ndev,

sparx5 = port->sparx5;
if (!tmo->rule && tmo->cookie) {
- err = vcap_enable_lookups(sparx5->vcap_ctrl, ndev, 0,
- tmo->cookie, false);
+ err = vcap_enable_lookups(sparx5->vcap_ctrl, ndev,
+ 0, 0, tmo->cookie, false);
if (err)
return err;
return 0;
@@ -80,12 +86,6 @@ int sparx5_tc_matchall(struct net_device *ndev,
struct tc_cls_matchall_offload *tmo,
bool ingress)
{
- if (!tc_cls_can_offload_and_chain0(ndev, &tmo->common)) {
- NL_SET_ERR_MSG_MOD(tmo->common.extack,
- "Only chain zero is supported");
- return -EOPNOTSUPP;
- }
-
switch (tmo->command) {
case TC_CLSMATCHALL_REPLACE:
return sparx5_tc_matchall_replace(ndev, tmo, ingress);
diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api.c b/drivers/net/ethernet/microchip/vcap/vcap_api.c
index 486ab2c2baaa..12807bc0d385 100644
--- a/drivers/net/ethernet/microchip/vcap/vcap_api.c
+++ b/drivers/net/ethernet/microchip/vcap/vcap_api.c
@@ -37,11 +37,13 @@ struct vcap_rule_move {
int count; /* blocksize of addresses to move */
};

-/* Stores the filter cookie that enabled the port */
+/* Stores the filter cookie and chain id that enabled the port */
struct vcap_enabled_port {
struct list_head list; /* for insertion in enabled ports list */
struct net_device *ndev; /* the enabled port */
unsigned long cookie; /* filter that enabled the port */
+ int src_cid; /* source chain id */
+ int dst_cid; /* destination chain id */
};

void vcap_iter_set(struct vcap_stream_iter *itr, int sw_width,
@@ -1930,6 +1932,21 @@ static void vcap_move_rules(struct vcap_rule_internal *ri,
move->offset, move->count);
}

+/* Check if the chain is already used to enable a VCAP lookup for this port */
+static bool vcap_is_chain_used(struct vcap_control *vctrl,
+ struct net_device *ndev, int src_cid)
+{
+ struct vcap_enabled_port *eport;
+ struct vcap_admin *admin;
+
+ list_for_each_entry(admin, &vctrl->list, list)
+ list_for_each_entry(eport, &admin->enabled, list)
+ if (eport->src_cid == src_cid && eport->ndev == ndev)
+ return true;
+
+ return false;
+}
+
/* Encode and write a validated rule to the VCAP */
int vcap_add_rule(struct vcap_rule *rule)
{
@@ -2593,23 +2610,33 @@ void vcap_set_tc_exterr(struct flow_cls_offload *fco, struct vcap_rule *vrule)
EXPORT_SYMBOL_GPL(vcap_set_tc_exterr);

/* Check if this port is already enabled for this VCAP instance */
-static bool vcap_is_enabled(struct vcap_admin *admin, struct net_device *ndev,
- unsigned long cookie)
+static bool vcap_is_enabled(struct vcap_control *vctrl, struct net_device *ndev,
+ int dst_cid)
{
struct vcap_enabled_port *eport;
+ struct vcap_admin *admin;

- list_for_each_entry(eport, &admin->enabled, list)
- if (eport->cookie == cookie || eport->ndev == ndev)
- return true;
+ list_for_each_entry(admin, &vctrl->list, list)
+ list_for_each_entry(eport, &admin->enabled, list)
+ if (eport->dst_cid == dst_cid && eport->ndev == ndev)
+ return true;

return false;
}

-/* Enable this port for this VCAP instance */
-static int vcap_enable(struct vcap_admin *admin, struct net_device *ndev,
- unsigned long cookie)
+/* Enable this port and chain id in a VCAP instance */
+static int vcap_enable(struct vcap_control *vctrl, struct net_device *ndev,
+ unsigned long cookie, int src_cid, int dst_cid)
{
struct vcap_enabled_port *eport;
+ struct vcap_admin *admin;
+
+ if (src_cid >= dst_cid)
+ return -EFAULT;
+
+ admin = vcap_find_admin(vctrl, dst_cid);
+ if (!admin)
+ return -ENOENT;

eport = kzalloc(sizeof(*eport), GFP_KERNEL);
if (!eport)
@@ -2617,48 +2644,49 @@ static int vcap_enable(struct vcap_admin *admin, struct net_device *ndev,

eport->ndev = ndev;
eport->cookie = cookie;
+ eport->src_cid = src_cid;
+ eport->dst_cid = dst_cid;
+ mutex_lock(&admin->lock);
list_add_tail(&eport->list, &admin->enabled);
+ mutex_unlock(&admin->lock);

return 0;
}

-/* Disable this port for this VCAP instance */
-static int vcap_disable(struct vcap_admin *admin, struct net_device *ndev,
+/* Disable this port and chain id for a VCAP instance */
+static int vcap_disable(struct vcap_control *vctrl, struct net_device *ndev,
unsigned long cookie)
{
- struct vcap_enabled_port *eport;
+ struct vcap_enabled_port *elem, *eport = NULL;
+ struct vcap_admin *found = NULL, *admin;

- list_for_each_entry(eport, &admin->enabled, list) {
- if (eport->cookie == cookie && eport->ndev == ndev) {
- list_del(&eport->list);
- kfree(eport);
- return 0;
+ list_for_each_entry(admin, &vctrl->list, list) {
+ list_for_each_entry(elem, &admin->enabled, list) {
+ if (elem->cookie == cookie && elem->ndev == ndev) {
+ eport = elem;
+ found = admin;
+ break;
+ }
}
+ if (eport)
+ break;
}

- return -ENOENT;
-}
-
-/* Find the VCAP instance that enabled the port using a specific filter */
-static struct vcap_admin *vcap_find_admin_by_cookie(struct vcap_control *vctrl,
- unsigned long cookie)
-{
- struct vcap_enabled_port *eport;
- struct vcap_admin *admin;
-
- list_for_each_entry(admin, &vctrl->list, list)
- list_for_each_entry(eport, &admin->enabled, list)
- if (eport->cookie == cookie)
- return admin;
+ if (!eport)
+ return -ENOENT;

- return NULL;
+ mutex_lock(&found->lock);
+ list_del(&eport->list);
+ mutex_unlock(&found->lock);
+ kfree(eport);
+ return 0;
}

-/* Enable/Disable the VCAP instance lookups. Chain id 0 means disable */
+/* Enable/Disable the VCAP instance lookups */
int vcap_enable_lookups(struct vcap_control *vctrl, struct net_device *ndev,
- int chain_id, unsigned long cookie, bool enable)
+ int src_cid, int dst_cid, unsigned long cookie,
+ bool enable)
{
- struct vcap_admin *admin;
int err;

err = vcap_api_check(vctrl);
@@ -2668,29 +2696,23 @@ int vcap_enable_lookups(struct vcap_control *vctrl, struct net_device *ndev,
if (!ndev)
return -ENODEV;

- if (chain_id)
- admin = vcap_find_admin(vctrl, chain_id);
- else
- admin = vcap_find_admin_by_cookie(vctrl, cookie);
- if (!admin)
- return -ENOENT;
-
- /* first instance and first chain */
- if (admin->vinst || chain_id > admin->first_cid)
+ /* Source and destination must be the first chain in a lookup */
+ if (src_cid % VCAP_CID_LOOKUP_SIZE)
+ return -EFAULT;
+ if (dst_cid % VCAP_CID_LOOKUP_SIZE)
return -EFAULT;

- if (chain_id) {
- if (vcap_is_enabled(admin, ndev, cookie))
+ if (enable) {
+ if (vcap_is_enabled(vctrl, ndev, dst_cid))
return -EADDRINUSE;
- mutex_lock(&admin->lock);
- vcap_enable(admin, ndev, cookie);
+ if (vcap_is_chain_used(vctrl, ndev, src_cid))
+ return -EADDRNOTAVAIL;
+ err = vcap_enable(vctrl, ndev, cookie, src_cid, dst_cid);
} else {
- mutex_lock(&admin->lock);
- vcap_disable(admin, ndev, cookie);
+ err = vcap_disable(vctrl, ndev, cookie);
}
- mutex_unlock(&admin->lock);

- return 0;
+ return err;
}
EXPORT_SYMBOL_GPL(vcap_enable_lookups);

diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_client.h b/drivers/net/ethernet/microchip/vcap/vcap_api_client.h
index 0319866f9c94..e07dc8d3c639 100644
--- a/drivers/net/ethernet/microchip/vcap/vcap_api_client.h
+++ b/drivers/net/ethernet/microchip/vcap/vcap_api_client.h
@@ -148,9 +148,10 @@ struct vcap_counter {
bool sticky;
};

-/* Enable/Disable the VCAP instance lookups. Chain id 0 means disable */
+/* Enable/Disable the VCAP instance lookups */
int vcap_enable_lookups(struct vcap_control *vctrl, struct net_device *ndev,
- int chain_id, unsigned long cookie, bool enable);
+ int from_cid, int to_cid, unsigned long cookie,
+ bool enable);

/* VCAP rule operations */
/* Allocate a rule and fill in the basic information */
--
2.39.0

2023-01-05 08:45:36

by Steen Hegelund

[permalink] [raw]
Subject: [PATCH net-next 8/8] net: microchip: vcap api: Enable/Disable rules via chains in VCAP HW

This supports that individual rules are enabled and disabled via chain
information.
This is done by keeping disabled rules in the VCAP list (cached) until they
are enabled, and only at this time are the rules written to the VCAP HW.

Fixes: 4426b78c626d ("net: lan966x: Add port keyset config and callback interface")
Signed-off-by: Horatiu Vultur <[email protected]>
Signed-off-by: Steen Hegelund <[email protected]>
---
.../net/ethernet/microchip/vcap/vcap_api.c | 195 +++++++++++++++++-
.../ethernet/microchip/vcap/vcap_api_client.h | 1 -
.../microchip/vcap/vcap_api_debugfs.c | 11 +-
.../ethernet/microchip/vcap/vcap_api_kunit.c | 11 +-
.../microchip/vcap/vcap_api_private.h | 3 +
5 files changed, 211 insertions(+), 10 deletions(-)

diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api.c b/drivers/net/ethernet/microchip/vcap/vcap_api.c
index 94df0e7b58ea..7cb7086248c3 100644
--- a/drivers/net/ethernet/microchip/vcap/vcap_api.c
+++ b/drivers/net/ethernet/microchip/vcap/vcap_api.c
@@ -2025,8 +2025,6 @@ static void vcap_rule_set_state(struct vcap_rule_internal *ri)
ri->state = VCAP_RS_ENABLED;
else
ri->state = VCAP_RS_DISABLED;
- /* For now always store directly in HW */
- ri->state = VCAP_RS_PERMANENT;
}

/* Encode and write a validated rule to the VCAP */
@@ -2709,6 +2707,119 @@ void vcap_set_tc_exterr(struct flow_cls_offload *fco, struct vcap_rule *vrule)
}
EXPORT_SYMBOL_GPL(vcap_set_tc_exterr);

+/* Write a rule to VCAP HW to enable it */
+static int vcap_enable_rule(struct vcap_rule_internal *ri)
+{
+ struct vcap_client_actionfield *af, *naf;
+ struct vcap_client_keyfield *kf, *nkf;
+
+ vcap_erase_cache(ri);
+ vcap_encode_rule(ri);
+ vcap_write_rule(ri);
+
+ /* Deallocate the list of keys and actions */
+ list_for_each_entry_safe(kf, nkf, &ri->data.keyfields, ctrl.list) {
+ list_del(&kf->ctrl.list);
+ kfree(kf);
+ }
+ list_for_each_entry_safe(af, naf, &ri->data.actionfields, ctrl.list) {
+ list_del(&af->ctrl.list);
+ kfree(af);
+ }
+ ri->state = VCAP_RS_ENABLED;
+ return 0;
+}
+
+/* Enable all disabled rules for a specific chain/port in the VCAP HW */
+static int vcap_enable_rules(struct vcap_control *vctrl,
+ struct net_device *ndev, int chain)
+{
+ struct vcap_rule_internal *ri;
+ struct vcap_admin *admin;
+ int err = 0;
+
+ list_for_each_entry(admin, &vctrl->list, list) {
+ if (!(chain >= admin->first_cid && chain <= admin->last_cid))
+ continue;
+
+ /* Found the admin, now find the offloadable rules */
+ mutex_lock(&admin->lock);
+ list_for_each_entry(ri, &admin->rules, list) {
+ if (ri->data.vcap_chain_id != chain)
+ continue;
+
+ if (ri->ndev != ndev)
+ continue;
+
+ if (ri->state != VCAP_RS_DISABLED)
+ continue;
+
+ err = vcap_enable_rule(ri);
+ if (err)
+ break;
+ }
+ mutex_unlock(&admin->lock);
+ if (err)
+ break;
+ }
+ return err;
+}
+
+/* Read and erase a rule from VCAP HW to disable it */
+static int vcap_disable_rule(struct vcap_rule_internal *ri)
+{
+ int err;
+
+ err = vcap_read_rule(ri);
+ if (err)
+ return err;
+ err = vcap_decode_keyset(ri);
+ if (err)
+ return err;
+ err = vcap_decode_actionset(ri);
+ if (err)
+ return err;
+
+ ri->state = VCAP_RS_DISABLED;
+ ri->vctrl->ops->init(ri->ndev, ri->admin, ri->addr, ri->size);
+ return 0;
+}
+
+/* Disable all enabled rules for a specific chain/port in the VCAP HW */
+static int vcap_disable_rules(struct vcap_control *vctrl,
+ struct net_device *ndev, int chain)
+{
+ struct vcap_rule_internal *ri;
+ struct vcap_admin *admin;
+ int err = 0;
+
+ list_for_each_entry(admin, &vctrl->list, list) {
+ if (!(chain >= admin->first_cid && chain <= admin->last_cid))
+ continue;
+
+ /* Found the admin, now find the rules on the chain */
+ mutex_lock(&admin->lock);
+ list_for_each_entry(ri, &admin->rules, list) {
+ if (ri->data.vcap_chain_id != chain)
+ continue;
+
+ if (ri->ndev != ndev)
+ continue;
+
+ if (ri->state != VCAP_RS_ENABLED)
+ continue;
+
+ err = vcap_disable_rule(ri);
+ if (err)
+ break;
+ }
+ mutex_unlock(&admin->lock);
+ if (err)
+ break;
+ }
+ return err;
+}
+
/* Check if this port is already enabled for this VCAP instance */
static bool vcap_is_enabled(struct vcap_control *vctrl, struct net_device *ndev,
int dst_cid)
@@ -2750,6 +2861,15 @@ static int vcap_enable(struct vcap_control *vctrl, struct net_device *ndev,
list_add_tail(&eport->list, &admin->enabled);
mutex_unlock(&admin->lock);

+ /* Enable chained lookups */
+ while (dst_cid) {
+ admin = vcap_find_admin(vctrl, dst_cid);
+ if (!admin)
+ return -ENOENT;
+
+ vcap_enable_rules(vctrl, ndev, dst_cid);
+ dst_cid = vcap_get_next_chain(vctrl, ndev, dst_cid);
+ }
return 0;
}

@@ -2759,6 +2879,7 @@ static int vcap_disable(struct vcap_control *vctrl, struct net_device *ndev,
{
struct vcap_enabled_port *elem, *eport = NULL;
struct vcap_admin *found = NULL, *admin;
+ int dst_cid;

list_for_each_entry(admin, &vctrl->list, list) {
list_for_each_entry(elem, &admin->enabled, list) {
@@ -2775,6 +2896,17 @@ static int vcap_disable(struct vcap_control *vctrl, struct net_device *ndev,
if (!eport)
return -ENOENT;

+ /* Disable chained lookups */
+ dst_cid = eport->dst_cid;
+ while (dst_cid) {
+ admin = vcap_find_admin(vctrl, dst_cid);
+ if (!admin)
+ return -ENOENT;
+
+ vcap_disable_rules(vctrl, ndev, dst_cid);
+ dst_cid = vcap_get_next_chain(vctrl, ndev, dst_cid);
+ }
+
mutex_lock(&found->lock);
list_del(&eport->list);
mutex_unlock(&found->lock);
@@ -2901,6 +3033,65 @@ int vcap_rule_get_counter(struct vcap_rule *rule, struct vcap_counter *ctr)
}
EXPORT_SYMBOL_GPL(vcap_rule_get_counter);

+/* Get a copy of a client key field */
+static int vcap_rule_get_key(struct vcap_rule *rule,
+ enum vcap_key_field key,
+ struct vcap_client_keyfield *ckf)
+{
+ struct vcap_client_keyfield *field;
+
+ field = vcap_find_keyfield(rule, key);
+ if (!field)
+ return -EINVAL;
+ memcpy(ckf, field, sizeof(*ckf));
+ INIT_LIST_HEAD(&ckf->ctrl.list);
+ return 0;
+}
+
+/* Get the keysets that matches the rule key type/mask */
+int vcap_rule_get_keysets(struct vcap_rule_internal *ri,
+ struct vcap_keyset_list *matches)
+{
+ struct vcap_control *vctrl = ri->vctrl;
+ enum vcap_type vt = ri->admin->vtype;
+ const struct vcap_set *keyfield_set;
+ struct vcap_client_keyfield kf = {};
+ u32 value, mask;
+ int err, idx;
+
+ err = vcap_rule_get_key(&ri->data, VCAP_KF_TYPE, &kf);
+ if (err)
+ return err;
+
+ if (kf.ctrl.type == VCAP_FIELD_BIT) {
+ value = kf.data.u1.value;
+ mask = kf.data.u1.mask;
+ } else if (kf.ctrl.type == VCAP_FIELD_U32) {
+ value = kf.data.u32.value;
+ mask = kf.data.u32.mask;
+ } else {
+ return -EINVAL;
+ }
+
+ keyfield_set = vctrl->vcaps[vt].keyfield_set;
+ for (idx = 0; idx < vctrl->vcaps[vt].keyfield_set_size; ++idx) {
+ if (keyfield_set[idx].sw_per_item != ri->keyset_sw)
+ continue;
+
+ if (keyfield_set[idx].type_id == (u8)-1) {
+ vcap_keyset_list_add(matches, idx);
+ continue;
+ }
+
+ if ((keyfield_set[idx].type_id & mask) == value)
+ vcap_keyset_list_add(matches, idx);
+ }
+ if (matches->cnt > 0)
+ return 0;
+
+ return -EINVAL;
+}
+
static int vcap_rule_mod_key(struct vcap_rule *rule,
enum vcap_key_field key,
enum vcap_field_type ftype,
diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_client.h b/drivers/net/ethernet/microchip/vcap/vcap_api_client.h
index f44228436051..b8980b22352f 100644
--- a/drivers/net/ethernet/microchip/vcap/vcap_api_client.h
+++ b/drivers/net/ethernet/microchip/vcap/vcap_api_client.h
@@ -264,5 +264,4 @@ int vcap_rule_mod_action_u32(struct vcap_rule *rule,
/* Get a 32 bit key field value and mask from the rule */
int vcap_rule_get_key_u32(struct vcap_rule *rule, enum vcap_key_field key,
u32 *value, u32 *mask);
-
#endif /* __VCAP_API_CLIENT__ */
diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs.c b/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs.c
index d6a09ce75e4f..dc06f6d4f513 100644
--- a/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs.c
+++ b/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs.c
@@ -164,10 +164,13 @@ static int vcap_debugfs_show_keysets(struct vcap_rule_internal *ri,
matches.cnt = 0;
matches.max = ARRAY_SIZE(keysets);

- err = vcap_find_keystream_keysets(ri->vctrl, admin->vtype,
- admin->cache.keystream,
- admin->cache.maskstream,
- false, 0, &matches);
+ if (ri->state == VCAP_RS_DISABLED)
+ err = vcap_rule_get_keysets(ri, &matches);
+ else
+ err = vcap_find_keystream_keysets(ri->vctrl, admin->vtype,
+ admin->cache.keystream,
+ admin->cache.maskstream,
+ false, 0, &matches);
if (err) {
pr_err("%s:%d: could not find valid keysets: %d\n",
__func__, __LINE__, err);
diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c b/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c
index fdef9102a9b3..22690c669028 100644
--- a/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c
+++ b/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c
@@ -1305,8 +1305,8 @@ static void vcap_api_encode_rule_test(struct kunit *test)

struct vcap_admin is2_admin = {
.vtype = VCAP_TYPE_IS2,
- .first_cid = 10000,
- .last_cid = 19999,
+ .first_cid = 8000000,
+ .last_cid = 8099999,
.lookups = 4,
.last_valid_addr = 3071,
.first_valid_addr = 0,
@@ -1319,7 +1319,7 @@ static void vcap_api_encode_rule_test(struct kunit *test)
};
struct vcap_rule *rule;
struct vcap_rule_internal *ri;
- int vcap_chain_id = 10005;
+ int vcap_chain_id = 8000000;
enum vcap_user user = VCAP_USER_VCAP_UTIL;
u16 priority = 10;
int id = 100;
@@ -1391,6 +1391,11 @@ static void vcap_api_encode_rule_test(struct kunit *test)
KUNIT_EXPECT_EQ(test, 2, ri->keyset_sw_regs);
KUNIT_EXPECT_EQ(test, 4, ri->actionset_sw_regs);

+ /* Enable lookup, so the rule will be written */
+ ret = vcap_enable_lookups(&test_vctrl, &test_netdev, 0,
+ rule->vcap_chain_id, rule->cookie, true);
+ KUNIT_EXPECT_EQ(test, 0, ret);
+
/* Add rule with write callback */
ret = vcap_add_rule(rule);
KUNIT_EXPECT_EQ(test, 0, ret);
diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_private.h b/drivers/net/ethernet/microchip/vcap/vcap_api_private.h
index ce35af9a853d..86542accffe6 100644
--- a/drivers/net/ethernet/microchip/vcap/vcap_api_private.h
+++ b/drivers/net/ethernet/microchip/vcap/vcap_api_private.h
@@ -115,4 +115,7 @@ int vcap_find_keystream_keysets(struct vcap_control *vctrl, enum vcap_type vt,
u32 *keystream, u32 *mskstream, bool mask,
int sw_max, struct vcap_keyset_list *kslist);

+/* Get the keysets that matches the rule key type/mask */
+int vcap_rule_get_keysets(struct vcap_rule_internal *ri,
+ struct vcap_keyset_list *matches);
#endif /* __VCAP_API_PRIVATE__ */
--
2.39.0

2023-01-05 08:48:49

by Steen Hegelund

[permalink] [raw]
Subject: [PATCH net-next 3/8] net: microchip: vcap api: Always enable VCAP lookups

This changes the VCAP lookups state to always be enabled so that it is
possible to add "internal" VCAP rules that must be available even though
the user has not yet enabled the VCAP chains via a TC matchall filter.

The API callback to enable and disable VCAP lookups is therefore removed.

Fixes: 4426b78c626d ("net: lan966x: Add port keyset config and callback interface")
Signed-off-by: Horatiu Vultur <[email protected]>
Signed-off-by: Steen Hegelund <[email protected]>
---
.../microchip/lan966x/lan966x_vcap_impl.c | 24 ++++-----------
.../microchip/sparx5/sparx5_vcap_debugfs.c | 2 +-
.../microchip/sparx5/sparx5_vcap_impl.c | 29 ++++---------------
.../net/ethernet/microchip/vcap/vcap_api.c | 6 +---
.../net/ethernet/microchip/vcap/vcap_api.h | 5 ----
.../microchip/vcap/vcap_api_debugfs_kunit.c | 9 +-----
.../ethernet/microchip/vcap/vcap_api_kunit.c | 9 +-----
7 files changed, 16 insertions(+), 68 deletions(-)

diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_impl.c b/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_impl.c
index d8dc9fbb81e1..76a9fb113f50 100644
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_impl.c
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_impl.c
@@ -95,10 +95,7 @@ lan966x_vcap_is2_get_port_keysets(struct net_device *dev, int lookup,
bool found = false;
u32 val;

- /* Check if the port keyset selection is enabled */
val = lan_rd(lan966x, ANA_VCAP_S2_CFG(port->chip_port));
- if (!ANA_VCAP_S2_CFG_ENA_GET(val))
- return -ENOENT;

/* Collect all keysets for the port in a list */
if (l3_proto == ETH_P_ALL)
@@ -393,20 +390,6 @@ static int lan966x_vcap_port_info(struct net_device *dev,
return 0;
}

-static int lan966x_vcap_enable(struct net_device *dev,
- struct vcap_admin *admin,
- bool enable)
-{
- struct lan966x_port *port = netdev_priv(dev);
- struct lan966x *lan966x = port->lan966x;
-
- lan_rmw(ANA_VCAP_S2_CFG_ENA_SET(enable),
- ANA_VCAP_S2_CFG_ENA,
- lan966x, ANA_VCAP_S2_CFG(port->chip_port));
-
- return 0;
-}
-
static struct vcap_operations lan966x_vcap_ops = {
.validate_keyset = lan966x_vcap_validate_keyset,
.add_default_fields = lan966x_vcap_add_default_fields,
@@ -417,7 +400,6 @@ static struct vcap_operations lan966x_vcap_ops = {
.update = lan966x_vcap_update,
.move = lan966x_vcap_move,
.port_info = lan966x_vcap_port_info,
- .enable = lan966x_vcap_enable,
};

static void lan966x_vcap_admin_free(struct vcap_admin *admin)
@@ -524,6 +506,12 @@ int lan966x_vcap_init(struct lan966x *lan966x)
list_add_tail(&admin->list, &ctrl->list);
}

+ for (int p = 0; p < lan966x->num_phys_ports; ++p)
+ if (lan966x->ports[p])
+ lan_rmw(ANA_VCAP_S2_CFG_ENA_SET(true),
+ ANA_VCAP_S2_CFG_ENA, lan966x,
+ ANA_VCAP_S2_CFG(lan966x->ports[p]->chip_port));
+
lan966x->vcap_ctrl = ctrl;

return 0;
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_debugfs.c b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_debugfs.c
index b91e05ffe2f4..c9423adc92ce 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_debugfs.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_debugfs.c
@@ -29,7 +29,7 @@ static void sparx5_vcap_port_keys(struct sparx5 *sparx5,
/* Get lookup state */
value = spx5_rd(sparx5, ANA_ACL_VCAP_S2_CFG(port->portno));
out->prf(out->dst, "\n state: ");
- if (ANA_ACL_VCAP_S2_CFG_SEC_ENA_GET(value))
+ if (ANA_ACL_VCAP_S2_CFG_SEC_ENA_GET(value) & BIT(lookup))
out->prf(out->dst, "on");
else
out->prf(out->dst, "off");
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c
index a0c126ba9a87..0d4b40997bb4 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c
@@ -510,28 +510,6 @@ static void sparx5_vcap_move(struct net_device *ndev, struct vcap_admin *admin,
sparx5_vcap_wait_super_update(sparx5);
}

-/* Enable all lookups in the VCAP instance */
-static int sparx5_vcap_enable(struct net_device *ndev,
- struct vcap_admin *admin,
- bool enable)
-{
- struct sparx5_port *port = netdev_priv(ndev);
- struct sparx5 *sparx5;
- int portno;
-
- sparx5 = port->sparx5;
- portno = port->portno;
-
- /* For now we only consider IS2 */
- if (enable)
- spx5_wr(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0xf), sparx5,
- ANA_ACL_VCAP_S2_CFG(portno));
- else
- spx5_wr(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0), sparx5,
- ANA_ACL_VCAP_S2_CFG(portno));
- return 0;
-}
-
/* API callback operations: only IS2 is supported for now */
static struct vcap_operations sparx5_vcap_ops = {
.validate_keyset = sparx5_vcap_validate_keyset,
@@ -543,7 +521,6 @@ static struct vcap_operations sparx5_vcap_ops = {
.update = sparx5_vcap_update,
.move = sparx5_vcap_move,
.port_info = sparx5_port_info,
- .enable = sparx5_vcap_enable,
};

/* Enable lookups per port and set the keyset generation: only IS2 for now */
@@ -568,6 +545,12 @@ static void sparx5_vcap_port_key_selection(struct sparx5 *sparx5,
ANA_ACL_VCAP_S2_KEY_SEL(portno, lookup));
}
}
+ /* IS2 lookups are in bit 0:3 */
+ for (portno = 0; portno < SPX5_PORTS; ++portno)
+ spx5_rmw(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0xf),
+ ANA_ACL_VCAP_S2_CFG_SEC_ENA,
+ sparx5,
+ ANA_ACL_VCAP_S2_CFG(portno));
}

/* Disable lookups per port and set the keyset generation: only IS2 for now */
diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api.c b/drivers/net/ethernet/microchip/vcap/vcap_api.c
index 67e0a3d9103a..9de5367fde42 100644
--- a/drivers/net/ethernet/microchip/vcap/vcap_api.c
+++ b/drivers/net/ethernet/microchip/vcap/vcap_api.c
@@ -738,7 +738,7 @@ int vcap_api_check(struct vcap_control *ctrl)
!ctrl->ops->add_default_fields || !ctrl->ops->cache_erase ||
!ctrl->ops->cache_write || !ctrl->ops->cache_read ||
!ctrl->ops->init || !ctrl->ops->update || !ctrl->ops->move ||
- !ctrl->ops->port_info || !ctrl->ops->enable) {
+ !ctrl->ops->port_info) {
pr_err("%s:%d: client operations are missing\n",
__func__, __LINE__);
return -ENOENT;
@@ -2654,10 +2654,6 @@ int vcap_enable_lookups(struct vcap_control *vctrl, struct net_device *ndev,
if (admin->vinst || chain_id > admin->first_cid)
return -EFAULT;

- err = vctrl->ops->enable(ndev, admin, enable);
- if (err)
- return err;
-
if (chain_id) {
if (vcap_is_enabled(admin, ndev, cookie))
return -EADDRINUSE;
diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api.h b/drivers/net/ethernet/microchip/vcap/vcap_api.h
index 689c7270f2a8..c61f13a65030 100644
--- a/drivers/net/ethernet/microchip/vcap/vcap_api.h
+++ b/drivers/net/ethernet/microchip/vcap/vcap_api.h
@@ -259,11 +259,6 @@ struct vcap_operations {
(struct net_device *ndev,
struct vcap_admin *admin,
struct vcap_output_print *out);
- /* enable/disable the lookups in a vcap instance */
- int (*enable)
- (struct net_device *ndev,
- struct vcap_admin *admin,
- bool enable);
};

/* VCAP API Client control interface */
diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs_kunit.c b/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs_kunit.c
index cf594668d5d9..bef0b28a4a50 100644
--- a/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs_kunit.c
+++ b/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs_kunit.c
@@ -221,13 +221,6 @@ static int vcap_test_port_info(struct net_device *ndev,
return 0;
}

-static int vcap_test_enable(struct net_device *ndev,
- struct vcap_admin *admin,
- bool enable)
-{
- return 0;
-}
-
static struct vcap_operations test_callbacks = {
.validate_keyset = test_val_keyset,
.add_default_fields = test_add_def_fields,
@@ -238,7 +231,6 @@ static struct vcap_operations test_callbacks = {
.update = test_cache_update,
.move = test_cache_move,
.port_info = vcap_test_port_info,
- .enable = vcap_test_enable,
};

static struct vcap_control test_vctrl = {
@@ -253,6 +245,7 @@ static void vcap_test_api_init(struct vcap_admin *admin)
INIT_LIST_HEAD(&test_vctrl.list);
INIT_LIST_HEAD(&admin->list);
INIT_LIST_HEAD(&admin->rules);
+ INIT_LIST_HEAD(&admin->enabled);
list_add_tail(&admin->list, &test_vctrl.list);
memset(test_updateaddr, 0, sizeof(test_updateaddr));
test_updateaddridx = 0;
diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c b/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c
index 944de5cb9114..cc6a62338162 100644
--- a/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c
+++ b/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c
@@ -211,13 +211,6 @@ static int vcap_test_port_info(struct net_device *ndev,
return 0;
}

-static int vcap_test_enable(struct net_device *ndev,
- struct vcap_admin *admin,
- bool enable)
-{
- return 0;
-}
-
static struct vcap_operations test_callbacks = {
.validate_keyset = test_val_keyset,
.add_default_fields = test_add_def_fields,
@@ -228,7 +221,6 @@ static struct vcap_operations test_callbacks = {
.update = test_cache_update,
.move = test_cache_move,
.port_info = vcap_test_port_info,
- .enable = vcap_test_enable,
};

static struct vcap_control test_vctrl = {
@@ -243,6 +235,7 @@ static void vcap_test_api_init(struct vcap_admin *admin)
INIT_LIST_HEAD(&test_vctrl.list);
INIT_LIST_HEAD(&admin->list);
INIT_LIST_HEAD(&admin->rules);
+ INIT_LIST_HEAD(&admin->enabled);
list_add_tail(&admin->list, &test_vctrl.list);
memset(test_updateaddr, 0, sizeof(test_updateaddr));
test_updateaddridx = 0;
--
2.39.0

2023-01-05 08:48:50

by Steen Hegelund

[permalink] [raw]
Subject: [PATCH net-next 1/8] net: microchip: vcap api: Erase VCAP cache before encoding rule

For consistency the VCAP cache area is erased just before the new rule is
being encoded.

Signed-off-by: Steen Hegelund <[email protected]>
---
drivers/net/ethernet/microchip/vcap/vcap_api.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api.c b/drivers/net/ethernet/microchip/vcap/vcap_api.c
index 664aae3e2acd..b9b6432f4094 100644
--- a/drivers/net/ethernet/microchip/vcap/vcap_api.c
+++ b/drivers/net/ethernet/microchip/vcap/vcap_api.c
@@ -1823,6 +1823,7 @@ int vcap_add_rule(struct vcap_rule *rule)
}
if (move.count > 0)
vcap_move_rules(ri, &move);
+ vcap_erase_cache(ri);
ret = vcap_encode_rule(ri);
if (ret) {
pr_err("%s:%d: rule encoding error: %d\n", __func__, __LINE__, ret);
@@ -1885,7 +1886,6 @@ struct vcap_rule *vcap_alloc_rule(struct vcap_control *vctrl,
ri->vctrl = vctrl; /* refer to the client */
if (vcap_set_rule_id(ri) == 0)
goto out_free;
- vcap_erase_cache(ri);
return (struct vcap_rule *)ri;

out_free:
--
2.39.0