Skip to content

Commit

Permalink
mlxsw: spectrum_acl: Implement TC block sharing
Browse files Browse the repository at this point in the history
Benefit from the prepared TC and in-driver ACL infrastructure and
introduce block sharing offload. For that, a new struct "block" is
introduced in spectrum_acl in order to hold a list of specific
block-port bindings.

Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Acked-by: David Ahern <dsahern@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Jiri Pirko authored and David S. Miller committed Jan 17, 2018
1 parent 02caf49 commit 3aaff32
Show file tree
Hide file tree
Showing 4 changed files with 401 additions and 95 deletions.
182 changes: 152 additions & 30 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum.c
Original file line number Diff line number Diff line change
Expand Up @@ -1747,72 +1747,186 @@ static int mlxsw_sp_setup_tc_cls_matchall(struct mlxsw_sp_port *mlxsw_sp_port,
}

static int
mlxsw_sp_setup_tc_cls_flower(struct mlxsw_sp_port *mlxsw_sp_port,
struct tc_cls_flower_offload *f,
bool ingress)
mlxsw_sp_setup_tc_cls_flower(struct mlxsw_sp_acl_block *acl_block,
struct tc_cls_flower_offload *f)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_acl_block_mlxsw_sp(acl_block);

switch (f->command) {
case TC_CLSFLOWER_REPLACE:
return mlxsw_sp_flower_replace(mlxsw_sp_port, ingress, f);
return mlxsw_sp_flower_replace(mlxsw_sp, acl_block, f);
case TC_CLSFLOWER_DESTROY:
mlxsw_sp_flower_destroy(mlxsw_sp_port, ingress, f);
mlxsw_sp_flower_destroy(mlxsw_sp, acl_block, f);
return 0;
case TC_CLSFLOWER_STATS:
return mlxsw_sp_flower_stats(mlxsw_sp_port, ingress, f);
return mlxsw_sp_flower_stats(mlxsw_sp, acl_block, f);
default:
return -EOPNOTSUPP;
}
}

static int mlxsw_sp_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
void *cb_priv, bool ingress)
static int mlxsw_sp_setup_tc_block_cb_matchall(enum tc_setup_type type,
void *type_data,
void *cb_priv, bool ingress)
{
struct mlxsw_sp_port *mlxsw_sp_port = cb_priv;

if (!tc_can_offload(mlxsw_sp_port->dev))
return -EOPNOTSUPP;

switch (type) {
case TC_SETUP_CLSMATCHALL:
if (!tc_can_offload(mlxsw_sp_port->dev))
return -EOPNOTSUPP;

return mlxsw_sp_setup_tc_cls_matchall(mlxsw_sp_port, type_data,
ingress);
case TC_SETUP_CLSFLOWER:
return mlxsw_sp_setup_tc_cls_flower(mlxsw_sp_port, type_data,
ingress);
return 0;
default:
return -EOPNOTSUPP;
}
}

static int mlxsw_sp_setup_tc_block_cb_ig(enum tc_setup_type type,
void *type_data, void *cb_priv)
static int mlxsw_sp_setup_tc_block_cb_matchall_ig(enum tc_setup_type type,
void *type_data,
void *cb_priv)
{
return mlxsw_sp_setup_tc_block_cb(type, type_data, cb_priv, true);
return mlxsw_sp_setup_tc_block_cb_matchall(type, type_data,
cb_priv, true);
}

static int mlxsw_sp_setup_tc_block_cb_eg(enum tc_setup_type type,
void *type_data, void *cb_priv)
static int mlxsw_sp_setup_tc_block_cb_matchall_eg(enum tc_setup_type type,
void *type_data,
void *cb_priv)
{
return mlxsw_sp_setup_tc_block_cb(type, type_data, cb_priv, false);
return mlxsw_sp_setup_tc_block_cb_matchall(type, type_data,
cb_priv, false);
}

static int mlxsw_sp_setup_tc_block_cb_flower(enum tc_setup_type type,
void *type_data, void *cb_priv)
{
struct mlxsw_sp_acl_block *acl_block = cb_priv;

switch (type) {
case TC_SETUP_CLSMATCHALL:
return 0;
case TC_SETUP_CLSFLOWER:
if (mlxsw_sp_acl_block_disabled(acl_block))
return -EOPNOTSUPP;

return mlxsw_sp_setup_tc_cls_flower(acl_block, type_data);
default:
return -EOPNOTSUPP;
}
}

static int
mlxsw_sp_setup_tc_block_flower_bind(struct mlxsw_sp_port *mlxsw_sp_port,
struct tcf_block *block, bool ingress)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
struct mlxsw_sp_acl_block *acl_block;
struct tcf_block_cb *block_cb;
int err;

block_cb = tcf_block_cb_lookup(block, mlxsw_sp_setup_tc_block_cb_flower,
mlxsw_sp);
if (!block_cb) {
acl_block = mlxsw_sp_acl_block_create(mlxsw_sp, block->net);
if (!acl_block)
return -ENOMEM;
block_cb = __tcf_block_cb_register(block,
mlxsw_sp_setup_tc_block_cb_flower,
mlxsw_sp, acl_block);
if (IS_ERR(block_cb)) {
err = PTR_ERR(block_cb);
goto err_cb_register;
}
} else {
acl_block = tcf_block_cb_priv(block_cb);
}
tcf_block_cb_incref(block_cb);
err = mlxsw_sp_acl_block_bind(mlxsw_sp, acl_block,
mlxsw_sp_port, ingress);
if (err)
goto err_block_bind;

if (ingress)
mlxsw_sp_port->ing_acl_block = acl_block;
else
mlxsw_sp_port->eg_acl_block = acl_block;

return 0;

err_block_bind:
if (!tcf_block_cb_decref(block_cb)) {
__tcf_block_cb_unregister(block_cb);
err_cb_register:
mlxsw_sp_acl_block_destroy(acl_block);
}
return err;
}

static void
mlxsw_sp_setup_tc_block_flower_unbind(struct mlxsw_sp_port *mlxsw_sp_port,
struct tcf_block *block, bool ingress)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
struct mlxsw_sp_acl_block *acl_block;
struct tcf_block_cb *block_cb;
int err;

block_cb = tcf_block_cb_lookup(block, mlxsw_sp_setup_tc_block_cb_flower,
mlxsw_sp);
if (!block_cb)
return;

if (ingress)
mlxsw_sp_port->ing_acl_block = NULL;
else
mlxsw_sp_port->eg_acl_block = NULL;

acl_block = tcf_block_cb_priv(block_cb);
err = mlxsw_sp_acl_block_unbind(mlxsw_sp, acl_block,
mlxsw_sp_port, ingress);
if (!err && !tcf_block_cb_decref(block_cb)) {
__tcf_block_cb_unregister(block_cb);
mlxsw_sp_acl_block_destroy(acl_block);
}
}

static int mlxsw_sp_setup_tc_block(struct mlxsw_sp_port *mlxsw_sp_port,
struct tc_block_offload *f)
{
tc_setup_cb_t *cb;
bool ingress;
int err;

if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
cb = mlxsw_sp_setup_tc_block_cb_ig;
else if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
cb = mlxsw_sp_setup_tc_block_cb_eg;
else
if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS) {
cb = mlxsw_sp_setup_tc_block_cb_matchall_ig;
ingress = true;
} else if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS) {
cb = mlxsw_sp_setup_tc_block_cb_matchall_eg;
ingress = false;
} else {
return -EOPNOTSUPP;
}

switch (f->command) {
case TC_BLOCK_BIND:
return tcf_block_cb_register(f->block, cb, mlxsw_sp_port,
mlxsw_sp_port);
err = tcf_block_cb_register(f->block, cb, mlxsw_sp_port,
mlxsw_sp_port);
if (err)
return err;
err = mlxsw_sp_setup_tc_block_flower_bind(mlxsw_sp_port,
f->block, ingress);
if (err) {
tcf_block_cb_unregister(f->block, cb, mlxsw_sp_port);
return err;
}
return 0;
case TC_BLOCK_UNBIND:
mlxsw_sp_setup_tc_block_flower_unbind(mlxsw_sp_port,
f->block, ingress);
tcf_block_cb_unregister(f->block, cb, mlxsw_sp_port);
return 0;
default:
Expand Down Expand Up @@ -1842,10 +1956,18 @@ static int mlxsw_sp_feature_hw_tc(struct net_device *dev, bool enable)
{
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);

if (!enable && (mlxsw_sp_port->acl_rule_count ||
!list_empty(&mlxsw_sp_port->mall_tc_list))) {
netdev_err(dev, "Active offloaded tc filters, can't turn hw_tc_offload off\n");
return -EINVAL;
if (!enable) {
if (mlxsw_sp_acl_block_rule_count(mlxsw_sp_port->ing_acl_block) ||
mlxsw_sp_acl_block_rule_count(mlxsw_sp_port->eg_acl_block) ||
!list_empty(&mlxsw_sp_port->mall_tc_list)) {
netdev_err(dev, "Active offloaded tc filters, can't turn hw_tc_offload off\n");
return -EINVAL;
}
mlxsw_sp_acl_block_disable_inc(mlxsw_sp_port->ing_acl_block);
mlxsw_sp_acl_block_disable_inc(mlxsw_sp_port->eg_acl_block);
} else {
mlxsw_sp_acl_block_disable_dec(mlxsw_sp_port->ing_acl_block);
mlxsw_sp_acl_block_disable_dec(mlxsw_sp_port->eg_acl_block);
}
return 0;
}
Expand Down
36 changes: 29 additions & 7 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum.h
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,8 @@ struct mlxsw_sp_port {
struct list_head vlans_list;
struct mlxsw_sp_qdisc *root_qdisc;
unsigned acl_rule_count;
struct mlxsw_sp_acl_block *ing_acl_block;
struct mlxsw_sp_acl_block *eg_acl_block;
};

static inline bool
Expand Down Expand Up @@ -490,17 +492,34 @@ struct mlxsw_sp_acl_ops {
enum mlxsw_sp_acl_profile profile);
};

struct mlxsw_sp_acl_block;
struct mlxsw_sp_acl_ruleset;

/* spectrum_acl.c */
struct mlxsw_afk *mlxsw_sp_acl_afk(struct mlxsw_sp_acl *acl);
struct mlxsw_sp *mlxsw_sp_acl_block_mlxsw_sp(struct mlxsw_sp_acl_block *block);
unsigned int mlxsw_sp_acl_block_rule_count(struct mlxsw_sp_acl_block *block);
void mlxsw_sp_acl_block_disable_inc(struct mlxsw_sp_acl_block *block);
void mlxsw_sp_acl_block_disable_dec(struct mlxsw_sp_acl_block *block);
bool mlxsw_sp_acl_block_disabled(struct mlxsw_sp_acl_block *block);
struct mlxsw_sp_acl_block *mlxsw_sp_acl_block_create(struct mlxsw_sp *mlxsw_sp,
struct net *net);
void mlxsw_sp_acl_block_destroy(struct mlxsw_sp_acl_block *block);
int mlxsw_sp_acl_block_bind(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_block *block,
struct mlxsw_sp_port *mlxsw_sp_port,
bool ingress);
int mlxsw_sp_acl_block_unbind(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_block *block,
struct mlxsw_sp_port *mlxsw_sp_port,
bool ingress);
struct mlxsw_sp_acl_ruleset *
mlxsw_sp_acl_ruleset_lookup(struct mlxsw_sp *mlxsw_sp, struct net_device *dev,
bool ingress, u32 chain_index,
mlxsw_sp_acl_ruleset_lookup(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_block *block, u32 chain_index,
enum mlxsw_sp_acl_profile profile);
struct mlxsw_sp_acl_ruleset *
mlxsw_sp_acl_ruleset_get(struct mlxsw_sp *mlxsw_sp, struct net_device *dev,
bool ingress, u32 chain_index,
mlxsw_sp_acl_ruleset_get(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_block *block, u32 chain_index,
enum mlxsw_sp_acl_profile profile);
void mlxsw_sp_acl_ruleset_put(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_ruleset *ruleset);
Expand Down Expand Up @@ -567,11 +586,14 @@ void mlxsw_sp_acl_fini(struct mlxsw_sp *mlxsw_sp);
extern const struct mlxsw_sp_acl_ops mlxsw_sp_acl_tcam_ops;

/* spectrum_flower.c */
int mlxsw_sp_flower_replace(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress,
int mlxsw_sp_flower_replace(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_block *block,
struct tc_cls_flower_offload *f);
void mlxsw_sp_flower_destroy(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress,
void mlxsw_sp_flower_destroy(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_block *block,
struct tc_cls_flower_offload *f);
int mlxsw_sp_flower_stats(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress,
int mlxsw_sp_flower_stats(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_block *block,
struct tc_cls_flower_offload *f);

/* spectrum_qdisc.c */
Expand Down
Loading

0 comments on commit 3aaff32

Please sign in to comment.