Skip to content

Commit

Permalink
net/mlx5e: Add indirect tc offload of ovs internal port
Browse files Browse the repository at this point in the history
Register callbacks for tc blocks of ovs internal port devices.

This allows an indirect offloading rules that apply on
such devices as the filter device.

In case a rule is added to a tc block of an internal port,
the mlx5 driver will implicitly add a matching on the internal
port's unique vport metadata value to the rule's matching list.
Therefore, only packets that previously hit a rule that redirects
to an internal port and got the vport metadata overwritten to the
internal port's unique metadata, can match on such indirect rule.

Offloading of both ingress and egress tc blocks of internal ports
is supported as opposed to other devices where only ingress block
offloading is supported.

Signed-off-by: Ariel Levkovich <lariel@nvidia.com>
Reviewed-by: Paul Blakey <paulb@nvidia.com>
Reviewed-by: Vlad Buslov <vladbu@nvidia.com>
Reviewed-by: Roi Dayan <roid@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
  • Loading branch information
Ariel Levkovich authored and Saeed Mahameed committed Oct 29, 2021
1 parent 100ad4e commit 166f431
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 19 deletions.
32 changes: 25 additions & 7 deletions drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
struct mlx5e_rep_indr_block_priv {
struct net_device *netdev;
struct mlx5e_rep_priv *rpriv;
enum flow_block_binder_type binder_type;

struct list_head list;
};
Expand Down Expand Up @@ -299,14 +300,16 @@ int mlx5e_rep_tc_event_port_affinity(struct mlx5e_priv *priv)

static struct mlx5e_rep_indr_block_priv *
mlx5e_rep_indr_block_priv_lookup(struct mlx5e_rep_priv *rpriv,
struct net_device *netdev)
struct net_device *netdev,
enum flow_block_binder_type binder_type)
{
struct mlx5e_rep_indr_block_priv *cb_priv;

list_for_each_entry(cb_priv,
&rpriv->uplink_priv.tc_indr_block_priv_list,
list)
if (cb_priv->netdev == netdev)
if (cb_priv->netdev == netdev &&
cb_priv->binder_type == binder_type)
return cb_priv;

return NULL;
Expand Down Expand Up @@ -344,9 +347,13 @@ mlx5e_rep_indr_offload(struct net_device *netdev,
static int mlx5e_rep_indr_setup_tc_cb(enum tc_setup_type type,
void *type_data, void *indr_priv)
{
unsigned long flags = MLX5_TC_FLAG(EGRESS) | MLX5_TC_FLAG(ESW_OFFLOAD);
unsigned long flags = MLX5_TC_FLAG(ESW_OFFLOAD);
struct mlx5e_rep_indr_block_priv *priv = indr_priv;

flags |= (priv->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS) ?
MLX5_TC_FLAG(EGRESS) :
MLX5_TC_FLAG(INGRESS);

switch (type) {
case TC_SETUP_CLSFLOWER:
return mlx5e_rep_indr_offload(priv->netdev, type_data, priv,
Expand Down Expand Up @@ -428,11 +435,14 @@ mlx5e_rep_indr_setup_block(struct net_device *netdev, struct Qdisc *sch,
void (*cleanup)(struct flow_block_cb *block_cb))
{
struct mlx5e_priv *priv = netdev_priv(rpriv->netdev);
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
bool is_ovs_int_port = netif_is_ovs_master(netdev);
struct mlx5e_rep_indr_block_priv *indr_priv;
struct flow_block_cb *block_cb;

if (!mlx5e_tc_tun_device_to_offload(priv, netdev) &&
!(is_vlan_dev(netdev) && vlan_dev_real_dev(netdev) == rpriv->netdev)) {
!(is_vlan_dev(netdev) && vlan_dev_real_dev(netdev) == rpriv->netdev) &&
!is_ovs_int_port) {
if (!(netif_is_macvlan(netdev) && macvlan_dev_real_dev(netdev) == rpriv->netdev))
return -EOPNOTSUPP;
if (!mlx5e_rep_macvlan_mode_supported(netdev)) {
Expand All @@ -441,15 +451,22 @@ mlx5e_rep_indr_setup_block(struct net_device *netdev, struct Qdisc *sch,
}
}

if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS &&
f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
return -EOPNOTSUPP;

if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS && !is_ovs_int_port)
return -EOPNOTSUPP;

if (is_ovs_int_port && !mlx5e_tc_int_port_supported(esw))
return -EOPNOTSUPP;

f->unlocked_driver_cb = true;
f->driver_block_list = &mlx5e_block_cb_list;

switch (f->command) {
case FLOW_BLOCK_BIND:
indr_priv = mlx5e_rep_indr_block_priv_lookup(rpriv, netdev);
indr_priv = mlx5e_rep_indr_block_priv_lookup(rpriv, netdev, f->binder_type);
if (indr_priv)
return -EEXIST;

Expand All @@ -459,6 +476,7 @@ mlx5e_rep_indr_setup_block(struct net_device *netdev, struct Qdisc *sch,

indr_priv->netdev = netdev;
indr_priv->rpriv = rpriv;
indr_priv->binder_type = f->binder_type;
list_add(&indr_priv->list,
&rpriv->uplink_priv.tc_indr_block_priv_list);

Expand All @@ -476,7 +494,7 @@ mlx5e_rep_indr_setup_block(struct net_device *netdev, struct Qdisc *sch,

return 0;
case FLOW_BLOCK_UNBIND:
indr_priv = mlx5e_rep_indr_block_priv_lookup(rpriv, netdev);
indr_priv = mlx5e_rep_indr_block_priv_lookup(rpriv, netdev, f->binder_type);
if (!indr_priv)
return -ENOENT;

Expand Down
36 changes: 33 additions & 3 deletions drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1437,6 +1437,32 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
parse_attr = attr->parse_attr;
esw_attr = attr->esw_attr;

if (netif_is_ovs_master(parse_attr->filter_dev)) {
struct mlx5e_tc_int_port *int_port;

if (attr->chain) {
NL_SET_ERR_MSG_MOD(extack,
"Internal port rule is only supported on chain 0");
return -EOPNOTSUPP;
}

if (attr->dest_chain) {
NL_SET_ERR_MSG_MOD(extack,
"Internal port rule offload doesn't support goto action");
return -EOPNOTSUPP;
}

int_port = mlx5e_tc_int_port_get(mlx5e_get_int_port_priv(priv),
parse_attr->filter_dev->ifindex,
flow_flag_test(flow, EGRESS) ?
MLX5E_TC_INT_PORT_EGRESS :
MLX5E_TC_INT_PORT_INGRESS);
if (IS_ERR(int_port))
return PTR_ERR(int_port);

esw_attr->int_port = int_port;
}

for (out_index = 0; out_index < MLX5_MAX_FLOW_FWD_VPORTS; out_index++) {
struct net_device *out_dev;
int mirred_ifindex;
Expand Down Expand Up @@ -1592,6 +1618,9 @@ static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv,
if (attr->action & MLX5_FLOW_CONTEXT_ACTION_COUNT)
mlx5_fc_destroy(esw_attr->counter_dev, attr->counter);

if (esw_attr->int_port)
mlx5e_tc_int_port_put(mlx5e_get_int_port_priv(priv), esw_attr->int_port);

if (esw_attr->dest_int_port)
mlx5e_tc_int_port_put(mlx5e_get_int_port_priv(priv), esw_attr->dest_int_port);

Expand Down Expand Up @@ -4254,10 +4283,11 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
}
}

/* If we forward to internal port we can only have 1 dest */
if (esw_attr->dest_int_port && esw_attr->out_count > 1) {
/* Forward to/from internal port can only have 1 dest */
if ((netif_is_ovs_master(parse_attr->filter_dev) || esw_attr->dest_int_port) &&
esw_attr->out_count > 1) {
NL_SET_ERR_MSG_MOD(extack,
"Redirect to internal port should be the only destination");
"Rules with internal port can have only one destination");
return -EOPNOTSUPP;
}

Expand Down
1 change: 1 addition & 0 deletions drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,7 @@ struct mlx5_esw_flow_attr {
struct mlx5_core_dev *in_mdev;
struct mlx5_core_dev *counter_dev;
struct mlx5e_tc_int_port *dest_int_port;
struct mlx5e_tc_int_port *int_port;

int split_count;
int out_count;
Expand Down
32 changes: 23 additions & 9 deletions drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,18 @@ mlx5_eswitch_set_rule_flow_source(struct mlx5_eswitch *esw,
struct mlx5_flow_spec *spec,
struct mlx5_esw_flow_attr *attr)
{
if (MLX5_CAP_ESW_FLOWTABLE(esw->dev, flow_source) &&
attr && attr->in_rep)
spec->flow_context.flow_source =
attr->in_rep->vport == MLX5_VPORT_UPLINK ?
MLX5_FLOW_CONTEXT_FLOW_SOURCE_UPLINK :
MLX5_FLOW_CONTEXT_FLOW_SOURCE_LOCAL_VPORT;
if (!MLX5_CAP_ESW_FLOWTABLE(esw->dev, flow_source) || !attr || !attr->in_rep)
return;

if (attr->int_port) {
spec->flow_context.flow_source = mlx5e_tc_int_port_get_flow_source(attr->int_port);

return;
}

spec->flow_context.flow_source = (attr->in_rep->vport == MLX5_VPORT_UPLINK) ?
MLX5_FLOW_CONTEXT_FLOW_SOURCE_UPLINK :
MLX5_FLOW_CONTEXT_FLOW_SOURCE_LOCAL_VPORT;
}

/* Actually only the upper 16 bits of reg c0 need to be cleared, but the lower 16 bits
Expand Down Expand Up @@ -121,6 +127,8 @@ mlx5_eswitch_set_rule_source_port(struct mlx5_eswitch *esw,
struct mlx5_eswitch *src_esw,
u16 vport)
{
struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
u32 metadata;
void *misc2;
void *misc;

Expand All @@ -130,10 +138,16 @@ mlx5_eswitch_set_rule_source_port(struct mlx5_eswitch *esw,
if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
if (mlx5_esw_indir_table_decap_vport(attr))
vport = mlx5_esw_indir_table_decap_vport(attr);

if (esw_attr->int_port)
metadata =
mlx5e_tc_int_port_get_metadata_for_match(esw_attr->int_port);
else
metadata =
mlx5_eswitch_get_vport_metadata_for_match(src_esw, vport);

misc2 = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters_2);
MLX5_SET(fte_match_set_misc2, misc2, metadata_reg_c_0,
mlx5_eswitch_get_vport_metadata_for_match(src_esw,
vport));
MLX5_SET(fte_match_set_misc2, misc2, metadata_reg_c_0, metadata);

misc2 = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters_2);
MLX5_SET(fte_match_set_misc2, misc2, metadata_reg_c_0,
Expand Down

0 comments on commit 166f431

Please sign in to comment.