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

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
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 33e3a273
......@@ -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;
}
......@@ -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,
......
......@@ -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);
......
......@@ -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);
......
......@@ -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)
{
......@@ -2595,23 +2612,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(admin, &vctrl->list, list)
list_for_each_entry(eport, &admin->enabled, list)
if (eport->cookie == cookie || eport->ndev == ndev)
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)
......@@ -2619,48 +2646,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;
}
if (!eport)
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;
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);
......@@ -2670,29 +2698,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);
......
......@@ -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 */
......
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