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: Vu Pham <vuhuong@mellanox.com> Reviewed-by: Parav Pandit <parav@mellanox.com> Reviewed-by: Roi Dayan <roid@mellanox.com> Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
This commit is contained in:
parent
07bab95026
commit
bf773dc0e6
|
@ -6,55 +6,165 @@
|
|||
#include "helper.h"
|
||||
#include "ofld.h"
|
||||
|
||||
static int esw_acl_egress_ofld_rules_create(struct mlx5_eswitch *esw,
|
||||
struct mlx5_vport *vport)
|
||||
static void esw_acl_egress_ofld_fwd2vport_destroy(struct mlx5_vport *vport)
|
||||
{
|
||||
if (!MLX5_CAP_GEN(esw->dev, prio_tag_required))
|
||||
return 0;
|
||||
if (!vport->egress.offloads.fwd_rule)
|
||||
return;
|
||||
|
||||
/* For prio tag mode, there is only 1 FTEs:
|
||||
* 1) prio tag packets - pop the prio tag VLAN, allow
|
||||
* Unmatched traffic is allowed by default
|
||||
*/
|
||||
esw_debug(esw->dev,
|
||||
"vport[%d] configure prio tag egress rules\n", vport->vport);
|
||||
mlx5_del_flow_rules(vport->egress.offloads.fwd_rule);
|
||||
vport->egress.offloads.fwd_rule = NULL;
|
||||
}
|
||||
|
||||
/* prio tag vlan rule - pop it so vport receives untagged packets */
|
||||
return esw_egress_acl_vlan_create(esw, vport, NULL, 0,
|
||||
MLX5_FLOW_CONTEXT_ACTION_VLAN_POP |
|
||||
MLX5_FLOW_CONTEXT_ACTION_ALLOW);
|
||||
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,
|
||||
struct mlx5_vport *vport,
|
||||
struct mlx5_flow_destination *fwd_dest)
|
||||
{
|
||||
int err = 0;
|
||||
int action;
|
||||
|
||||
if (MLX5_CAP_GEN(esw->dev, prio_tag_required)) {
|
||||
/* For prio tag mode, there is only 1 FTEs:
|
||||
* 1) prio tag packets - pop the prio tag VLAN, allow
|
||||
* Unmatched traffic is allowed by default
|
||||
*/
|
||||
esw_debug(esw->dev,
|
||||
"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 */
|
||||
err = esw_egress_acl_vlan_create(esw, vport, fwd_dest, 0, action);
|
||||
if (err)
|
||||
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)
|
||||
{
|
||||
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,
|
||||
struct mlx5_vport *vport)
|
||||
{
|
||||
if (!MLX5_CAP_GEN(esw->dev, prio_tag_required))
|
||||
return 0;
|
||||
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;
|
||||
|
||||
return esw_acl_egress_vlan_grp_create(esw, vport);
|
||||
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;
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
int esw_acl_egress_ofld_setup(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
|
||||
{
|
||||
int table_size = 0;
|
||||
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;
|
||||
|
||||
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,
|
||||
MLX5_FLOW_NAMESPACE_ESW_EGRESS, 0);
|
||||
MLX5_FLOW_NAMESPACE_ESW_EGRESS, table_size);
|
||||
if (IS_ERR_OR_NULL(vport->egress.acl)) {
|
||||
err = PTR_ERR(vport->egress.acl);
|
||||
vport->egress.acl = NULL;
|
||||
|
@ -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);
|
||||
|
||||
err = esw_acl_egress_ofld_rules_create(esw, vport);
|
||||
err = esw_acl_egress_ofld_rules_create(esw, vport, NULL);
|
||||
if (err)
|
||||
goto rules_err;
|
||||
|
||||
|
@ -86,3 +196,40 @@ void esw_acl_egress_ofld_cleanup(struct mlx5_vport *vport)
|
|||
esw_acl_egress_ofld_groups_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 @@
|
|||
/* Eswitch acl egress external APIs */
|
||||
int esw_acl_egress_ofld_setup(struct mlx5_eswitch *esw, 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 */
|
||||
int esw_acl_ingress_ofld_setup(struct mlx5_eswitch *esw, struct mlx5_vport *vport);
|
||||
|
|
|
@ -101,11 +101,17 @@ struct vport_egress {
|
|||
struct mlx5_flow_table *acl;
|
||||
struct mlx5_flow_handle *allowed_vlan;
|
||||
struct mlx5_flow_group *vlan_grp;
|
||||
struct {
|
||||
struct mlx5_flow_group *drop_grp;
|
||||
struct mlx5_flow_handle *drop_rule;
|
||||
struct mlx5_fc *drop_counter;
|
||||
} legacy;
|
||||
union {
|
||||
struct {
|
||||
struct mlx5_flow_group *drop_grp;
|
||||
struct mlx5_flow_handle *drop_rule;
|
||||
struct mlx5_fc *drop_counter;
|
||||
} legacy;
|
||||
struct {
|
||||
struct mlx5_flow_group *fwd_grp;
|
||||
struct mlx5_flow_handle *fwd_rule;
|
||||
} offloads;
|
||||
};
|
||||
};
|
||||
|
||||
struct mlx5_vport_drop_stats {
|
||||
|
|
Loading…
Reference in New Issue