Commit bf773dc0 authored by Vu Pham's avatar Vu Pham Committed by Saeed Mahameed

net/mlx5: E-Switch, Introduce APIs to enable egress acl forward-to-vport rule

By default, e-switch vport's egress acl just forward packets to its
counterpart NIC vport using existing egress acl table.

During port failover in bonding scenario where two VFs representors
are bonded, the egress acl forward-to-vport rule will be added to
the existing egress acl table of e-switch vport of passive/inactive
slave representor to forward packets to other NIC vport ie. the active
slave representor's NIC vport to handle egress "failover" traffic.

Enable egress acl and have APIs to create and destroy egress acl
forward-to-vport rule and group.
Signed-off-by: default avatarVu Pham <vuhuong@mellanox.com>
Reviewed-by: default avatarParav Pandit <parav@mellanox.com>
Reviewed-by: default avatarRoi Dayan <roid@mellanox.com>
Signed-off-by: default avatarSaeed Mahameed <saeedm@mellanox.com>
parent 07bab950
...@@ -6,12 +6,52 @@ ...@@ -6,12 +6,52 @@
#include "helper.h" #include "helper.h"
#include "ofld.h" #include "ofld.h"
static void esw_acl_egress_ofld_fwd2vport_destroy(struct mlx5_vport *vport)
{
if (!vport->egress.offloads.fwd_rule)
return;
mlx5_del_flow_rules(vport->egress.offloads.fwd_rule);
vport->egress.offloads.fwd_rule = NULL;
}
static int esw_acl_egress_ofld_fwd2vport_create(struct mlx5_eswitch *esw,
struct mlx5_vport *vport,
struct mlx5_flow_destination *fwd_dest)
{
struct mlx5_flow_act flow_act = {};
int err = 0;
esw_debug(esw->dev, "vport(%d) configure egress acl rule fwd2vport(%d)\n",
vport->vport, fwd_dest->vport.num);
/* Delete the old egress forward-to-vport rule if any */
esw_acl_egress_ofld_fwd2vport_destroy(vport);
flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
vport->egress.offloads.fwd_rule =
mlx5_add_flow_rules(vport->egress.acl, NULL,
&flow_act, fwd_dest, 1);
if (IS_ERR(vport->egress.offloads.fwd_rule)) {
err = PTR_ERR(vport->egress.offloads.fwd_rule);
esw_warn(esw->dev,
"vport(%d) failed to add fwd2vport acl rule err(%d)\n",
vport->vport, err);
vport->egress.offloads.fwd_rule = NULL;
}
return err;
}
static int esw_acl_egress_ofld_rules_create(struct mlx5_eswitch *esw, static int esw_acl_egress_ofld_rules_create(struct mlx5_eswitch *esw,
struct mlx5_vport *vport) struct mlx5_vport *vport,
struct mlx5_flow_destination *fwd_dest)
{ {
if (!MLX5_CAP_GEN(esw->dev, prio_tag_required)) int err = 0;
return 0; int action;
if (MLX5_CAP_GEN(esw->dev, prio_tag_required)) {
/* For prio tag mode, there is only 1 FTEs: /* For prio tag mode, there is only 1 FTEs:
* 1) prio tag packets - pop the prio tag VLAN, allow * 1) prio tag packets - pop the prio tag VLAN, allow
* Unmatched traffic is allowed by default * Unmatched traffic is allowed by default
...@@ -19,42 +59,112 @@ static int esw_acl_egress_ofld_rules_create(struct mlx5_eswitch *esw, ...@@ -19,42 +59,112 @@ static int esw_acl_egress_ofld_rules_create(struct mlx5_eswitch *esw,
esw_debug(esw->dev, esw_debug(esw->dev,
"vport[%d] configure prio tag egress rules\n", vport->vport); "vport[%d] configure prio tag egress rules\n", vport->vport);
action = MLX5_FLOW_CONTEXT_ACTION_VLAN_POP;
action |= fwd_dest ? MLX5_FLOW_CONTEXT_ACTION_FWD_DEST :
MLX5_FLOW_CONTEXT_ACTION_ALLOW;
/* prio tag vlan rule - pop it so vport receives untagged packets */ /* prio tag vlan rule - pop it so vport receives untagged packets */
return esw_egress_acl_vlan_create(esw, vport, NULL, 0, err = esw_egress_acl_vlan_create(esw, vport, fwd_dest, 0, action);
MLX5_FLOW_CONTEXT_ACTION_VLAN_POP | if (err)
MLX5_FLOW_CONTEXT_ACTION_ALLOW); goto prio_err;
}
if (fwd_dest) {
err = esw_acl_egress_ofld_fwd2vport_create(esw, vport, fwd_dest);
if (err)
goto fwd_err;
}
return 0;
fwd_err:
esw_acl_egress_vlan_destroy(vport);
prio_err:
return err;
} }
static void esw_acl_egress_ofld_rules_destroy(struct mlx5_vport *vport) static void esw_acl_egress_ofld_rules_destroy(struct mlx5_vport *vport)
{ {
esw_acl_egress_vlan_destroy(vport); esw_acl_egress_vlan_destroy(vport);
esw_acl_egress_ofld_fwd2vport_destroy(vport);
} }
static int esw_acl_egress_ofld_groups_create(struct mlx5_eswitch *esw, static int esw_acl_egress_ofld_groups_create(struct mlx5_eswitch *esw,
struct mlx5_vport *vport) struct mlx5_vport *vport)
{ {
if (!MLX5_CAP_GEN(esw->dev, prio_tag_required)) int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
struct mlx5_flow_group *fwd_grp;
u32 *flow_group_in;
u32 flow_index = 0;
int ret = 0;
if (MLX5_CAP_GEN(esw->dev, prio_tag_required)) {
ret = esw_acl_egress_vlan_grp_create(esw, vport);
if (ret)
return ret;
flow_index++;
}
if (!mlx5_esw_acl_egress_fwd2vport_supported(esw))
goto out;
flow_group_in = kvzalloc(inlen, GFP_KERNEL);
if (!flow_group_in) {
ret = -ENOMEM;
goto fwd_grp_err;
}
/* This group holds 1 FTE to forward all packets to other vport
* when bond vports is supported.
*/
MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, flow_index);
MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, flow_index);
fwd_grp = mlx5_create_flow_group(vport->egress.acl, flow_group_in);
if (IS_ERR(fwd_grp)) {
ret = PTR_ERR(fwd_grp);
esw_warn(esw->dev,
"Failed to create vport[%d] egress fwd2vport flow group, err(%d)\n",
vport->vport, ret);
kvfree(flow_group_in);
goto fwd_grp_err;
}
vport->egress.offloads.fwd_grp = fwd_grp;
kvfree(flow_group_in);
return 0; return 0;
return esw_acl_egress_vlan_grp_create(esw, vport); fwd_grp_err:
esw_acl_egress_vlan_grp_destroy(vport);
out:
return ret;
} }
static void esw_acl_egress_ofld_groups_destroy(struct mlx5_vport *vport) static void esw_acl_egress_ofld_groups_destroy(struct mlx5_vport *vport)
{ {
if (!IS_ERR_OR_NULL(vport->egress.offloads.fwd_grp)) {
mlx5_destroy_flow_group(vport->egress.offloads.fwd_grp);
vport->egress.offloads.fwd_grp = NULL;
}
esw_acl_egress_vlan_grp_destroy(vport); esw_acl_egress_vlan_grp_destroy(vport);
} }
int esw_acl_egress_ofld_setup(struct mlx5_eswitch *esw, struct mlx5_vport *vport) int esw_acl_egress_ofld_setup(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
{ {
int table_size = 0;
int err; int err;
if (!MLX5_CAP_GEN(esw->dev, prio_tag_required)) if (!mlx5_esw_acl_egress_fwd2vport_supported(esw) &&
!MLX5_CAP_GEN(esw->dev, prio_tag_required))
return 0; return 0;
esw_acl_egress_ofld_rules_destroy(vport); esw_acl_egress_ofld_rules_destroy(vport);
if (mlx5_esw_acl_egress_fwd2vport_supported(esw))
table_size++;
if (MLX5_CAP_GEN(esw->dev, prio_tag_required))
table_size++;
vport->egress.acl = esw_acl_table_create(esw, vport->vport, vport->egress.acl = esw_acl_table_create(esw, vport->vport,
MLX5_FLOW_NAMESPACE_ESW_EGRESS, 0); MLX5_FLOW_NAMESPACE_ESW_EGRESS, table_size);
if (IS_ERR_OR_NULL(vport->egress.acl)) { if (IS_ERR_OR_NULL(vport->egress.acl)) {
err = PTR_ERR(vport->egress.acl); err = PTR_ERR(vport->egress.acl);
vport->egress.acl = NULL; vport->egress.acl = NULL;
...@@ -67,7 +177,7 @@ int esw_acl_egress_ofld_setup(struct mlx5_eswitch *esw, struct mlx5_vport *vport ...@@ -67,7 +177,7 @@ int esw_acl_egress_ofld_setup(struct mlx5_eswitch *esw, struct mlx5_vport *vport
esw_debug(esw->dev, "vport[%d] configure egress rules\n", vport->vport); esw_debug(esw->dev, "vport[%d] configure egress rules\n", vport->vport);
err = esw_acl_egress_ofld_rules_create(esw, vport); err = esw_acl_egress_ofld_rules_create(esw, vport, NULL);
if (err) if (err)
goto rules_err; goto rules_err;
...@@ -86,3 +196,40 @@ void esw_acl_egress_ofld_cleanup(struct mlx5_vport *vport) ...@@ -86,3 +196,40 @@ void esw_acl_egress_ofld_cleanup(struct mlx5_vport *vport)
esw_acl_egress_ofld_groups_destroy(vport); esw_acl_egress_ofld_groups_destroy(vport);
esw_acl_egress_table_destroy(vport); esw_acl_egress_table_destroy(vport);
} }
int mlx5_esw_acl_egress_vport_bond(struct mlx5_eswitch *esw, u16 active_vport_num,
u16 passive_vport_num)
{
struct mlx5_vport *passive_vport = mlx5_eswitch_get_vport(esw, passive_vport_num);
struct mlx5_vport *active_vport = mlx5_eswitch_get_vport(esw, active_vport_num);
struct mlx5_flow_destination fwd_dest = {};
if (IS_ERR(active_vport))
return PTR_ERR(active_vport);
if (IS_ERR(passive_vport))
return PTR_ERR(passive_vport);
/* Cleanup and recreate rules WITHOUT fwd2vport of active vport */
esw_acl_egress_ofld_rules_destroy(active_vport);
esw_acl_egress_ofld_rules_create(esw, active_vport, NULL);
/* Cleanup and recreate all rules + fwd2vport rule of passive vport to forward */
esw_acl_egress_ofld_rules_destroy(passive_vport);
fwd_dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
fwd_dest.vport.num = active_vport_num;
fwd_dest.vport.vhca_id = MLX5_CAP_GEN(esw->dev, vhca_id);
fwd_dest.vport.flags = MLX5_FLOW_DEST_VPORT_VHCA_ID;
return esw_acl_egress_ofld_rules_create(esw, passive_vport, &fwd_dest);
}
int mlx5_esw_acl_egress_vport_unbond(struct mlx5_eswitch *esw, u16 vport_num)
{
struct mlx5_vport *vport = mlx5_eswitch_get_vport(esw, vport_num);
if (IS_ERR(vport))
return PTR_ERR(vport);
esw_acl_egress_ofld_rules_destroy(vport);
return esw_acl_egress_ofld_rules_create(esw, vport, NULL);
}
...@@ -9,6 +9,16 @@ ...@@ -9,6 +9,16 @@
/* Eswitch acl egress external APIs */ /* Eswitch acl egress external APIs */
int esw_acl_egress_ofld_setup(struct mlx5_eswitch *esw, struct mlx5_vport *vport); int esw_acl_egress_ofld_setup(struct mlx5_eswitch *esw, struct mlx5_vport *vport);
void esw_acl_egress_ofld_cleanup(struct mlx5_vport *vport); void esw_acl_egress_ofld_cleanup(struct mlx5_vport *vport);
int mlx5_esw_acl_egress_vport_bond(struct mlx5_eswitch *esw, u16 active_vport_num,
u16 passive_vport_num);
int mlx5_esw_acl_egress_vport_unbond(struct mlx5_eswitch *esw, u16 vport_num);
static inline bool mlx5_esw_acl_egress_fwd2vport_supported(struct mlx5_eswitch *esw)
{
return esw && esw->mode == MLX5_ESWITCH_OFFLOADS &&
mlx5_eswitch_vport_match_metadata_enabled(esw) &&
MLX5_CAP_ESW_FLOWTABLE(esw->dev, egress_acl_forward_to_vport);
}
/* Eswitch acl ingress external APIs */ /* Eswitch acl ingress external APIs */
int esw_acl_ingress_ofld_setup(struct mlx5_eswitch *esw, struct mlx5_vport *vport); int esw_acl_ingress_ofld_setup(struct mlx5_eswitch *esw, struct mlx5_vport *vport);
......
...@@ -101,11 +101,17 @@ struct vport_egress { ...@@ -101,11 +101,17 @@ struct vport_egress {
struct mlx5_flow_table *acl; struct mlx5_flow_table *acl;
struct mlx5_flow_handle *allowed_vlan; struct mlx5_flow_handle *allowed_vlan;
struct mlx5_flow_group *vlan_grp; struct mlx5_flow_group *vlan_grp;
union {
struct { struct {
struct mlx5_flow_group *drop_grp; struct mlx5_flow_group *drop_grp;
struct mlx5_flow_handle *drop_rule; struct mlx5_flow_handle *drop_rule;
struct mlx5_fc *drop_counter; struct mlx5_fc *drop_counter;
} legacy; } legacy;
struct {
struct mlx5_flow_group *fwd_grp;
struct mlx5_flow_handle *fwd_rule;
} offloads;
};
}; };
struct mlx5_vport_drop_stats { struct mlx5_vport_drop_stats {
......
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