Skip to content

Commit 9da611d

Browse files
Saeed MahameedPaolo Abeni
authored andcommitted
net/mlx5: E-Switch, support eswitch inactive mode
Add support for eswitch switchdev inactive mode Inactive mode: Drop all traffic going to FDB, Remove mpfs l2 rules and disconnect adjacent vports. Active mode: Traffic flows through FDB, mpfs table populated, and adjacent vports are connected. Signed-off-by: Saeed Mahameed <[email protected]> Signed-off-by: Adithya Jayachandran <[email protected]> Reviewed-by: Jiri Pirko <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
1 parent 9902b63 commit 9da611d

File tree

6 files changed

+214
-22
lines changed

6 files changed

+214
-22
lines changed

drivers/net/ethernet/mellanox/mlx5/core/esw/adj_vport.c

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,8 @@
44
#include "fs_core.h"
55
#include "eswitch.h"
66

7-
enum {
8-
MLX5_ADJ_VPORT_DISCONNECT = 0x0,
9-
MLX5_ADJ_VPORT_CONNECT = 0x1,
10-
};
11-
12-
static int mlx5_esw_adj_vport_modify(struct mlx5_core_dev *dev,
13-
u16 vport, bool connect)
7+
int mlx5_esw_adj_vport_modify(struct mlx5_core_dev *dev, u16 vport,
8+
bool connect)
149
{
1510
u32 in[MLX5_ST_SZ_DW(modify_vport_state_in)] = {};
1611

@@ -24,7 +19,7 @@ static int mlx5_esw_adj_vport_modify(struct mlx5_core_dev *dev,
2419
MLX5_SET(modify_vport_state_in, in, egress_connect_valid, 1);
2520
MLX5_SET(modify_vport_state_in, in, ingress_connect, connect);
2621
MLX5_SET(modify_vport_state_in, in, egress_connect, connect);
27-
22+
MLX5_SET(modify_vport_state_in, in, admin_state, connect);
2823
return mlx5_cmd_exec_in(dev, modify_vport_state, in);
2924
}
3025

@@ -96,7 +91,6 @@ static int mlx5_esw_adj_vport_create(struct mlx5_eswitch *esw, u16 vhca_id,
9691
if (err)
9792
goto acl_ns_remove;
9893

99-
mlx5_esw_adj_vport_modify(esw->dev, vport_num, MLX5_ADJ_VPORT_CONNECT);
10094
return 0;
10195

10296
acl_ns_remove:
@@ -117,8 +111,7 @@ static void mlx5_esw_adj_vport_destroy(struct mlx5_eswitch *esw,
117111

118112
esw_debug(esw->dev, "Destroying adjacent vport %d for vhca_id 0x%x\n",
119113
vport_num, vport->vhca_id);
120-
mlx5_esw_adj_vport_modify(esw->dev, vport_num,
121-
MLX5_ADJ_VPORT_DISCONNECT);
114+
122115
mlx5_esw_offloads_rep_remove(esw, vport);
123116
mlx5_fs_vport_egress_acl_ns_remove(esw->dev->priv.steering,
124117
vport->index);

drivers/net/ethernet/mellanox/mlx5/core/eswitch.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,9 @@ struct mlx5_eswitch_fdb {
264264

265265
struct offloads_fdb {
266266
struct mlx5_flow_namespace *ns;
267+
struct mlx5_flow_table *drop_root;
268+
struct mlx5_flow_handle *drop_root_rule;
269+
struct mlx5_fc *drop_root_fc;
267270
struct mlx5_flow_table *tc_miss_table;
268271
struct mlx5_flow_table *slow_fdb;
269272
struct mlx5_flow_group *send_to_vport_grp;
@@ -392,6 +395,7 @@ struct mlx5_eswitch {
392395
struct mlx5_esw_offload offloads;
393396
u32 last_vport_idx;
394397
int mode;
398+
bool offloads_inactive;
395399
u16 manager_vport;
396400
u16 first_host_vport;
397401
u8 num_peers;
@@ -634,6 +638,8 @@ const u32 *mlx5_esw_query_functions(struct mlx5_core_dev *dev);
634638

635639
void mlx5_esw_adjacent_vhcas_setup(struct mlx5_eswitch *esw);
636640
void mlx5_esw_adjacent_vhcas_cleanup(struct mlx5_eswitch *esw);
641+
int mlx5_esw_adj_vport_modify(struct mlx5_core_dev *dev, u16 vport,
642+
bool connect);
637643

638644
#define MLX5_DEBUG_ESWITCH_MASK BIT(3)
639645

drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c

Lines changed: 197 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1577,6 +1577,7 @@ esw_chains_create(struct mlx5_eswitch *esw, struct mlx5_flow_table *miss_fdb)
15771577
attr.max_grp_num = esw->params.large_group_num;
15781578
attr.default_ft = miss_fdb;
15791579
attr.mapping = esw->offloads.reg_c0_obj_pool;
1580+
attr.fs_base_prio = FDB_BYPASS_PATH;
15801581

15811582
chains = mlx5_chains_create(dev, &attr);
15821583
if (IS_ERR(chains)) {
@@ -2355,6 +2356,131 @@ static void esw_mode_change(struct mlx5_eswitch *esw, u16 mode)
23552356
mlx5_devcom_comp_unlock(esw->dev->priv.hca_devcom_comp);
23562357
}
23572358

2359+
static void mlx5_esw_fdb_drop_destroy(struct mlx5_eswitch *esw)
2360+
{
2361+
if (!esw->fdb_table.offloads.drop_root)
2362+
return;
2363+
2364+
esw_debug(esw->dev, "Destroying FDB drop root table %#x fc %#x\n",
2365+
esw->fdb_table.offloads.drop_root->id,
2366+
esw->fdb_table.offloads.drop_root_fc->id);
2367+
mlx5_del_flow_rules(esw->fdb_table.offloads.drop_root_rule);
2368+
/* Don't free flow counter here, can be reused on a later activation */
2369+
mlx5_destroy_flow_table(esw->fdb_table.offloads.drop_root);
2370+
esw->fdb_table.offloads.drop_root_rule = NULL;
2371+
esw->fdb_table.offloads.drop_root = NULL;
2372+
}
2373+
2374+
static int mlx5_esw_fdb_drop_create(struct mlx5_eswitch *esw)
2375+
{
2376+
struct mlx5_flow_destination drop_fc_dst = {};
2377+
struct mlx5_flow_table_attr ft_attr = {};
2378+
struct mlx5_flow_destination *dst = NULL;
2379+
struct mlx5_core_dev *dev = esw->dev;
2380+
struct mlx5_flow_namespace *root_ns;
2381+
struct mlx5_flow_act flow_act = {};
2382+
struct mlx5_flow_handle *flow_rule;
2383+
struct mlx5_flow_table *table;
2384+
int err = 0, dst_num = 0;
2385+
2386+
if (esw->fdb_table.offloads.drop_root)
2387+
return 0;
2388+
2389+
root_ns = esw->fdb_table.offloads.ns;
2390+
2391+
ft_attr.prio = FDB_DROP_ROOT;
2392+
ft_attr.max_fte = 1;
2393+
ft_attr.autogroup.max_num_groups = 1;
2394+
table = mlx5_create_auto_grouped_flow_table(root_ns, &ft_attr);
2395+
if (IS_ERR(table)) {
2396+
esw_warn(dev, "Failed to create fdb drop root table, err %pe\n",
2397+
table);
2398+
return PTR_ERR(table);
2399+
}
2400+
2401+
/* Drop FC reusable, create once on first deactivation of FDB */
2402+
if (!esw->fdb_table.offloads.drop_root_fc) {
2403+
struct mlx5_fc *counter = mlx5_fc_create(dev, 0);
2404+
2405+
err = PTR_ERR_OR_ZERO(counter);
2406+
if (err)
2407+
esw_warn(esw->dev, "create fdb drop fc err %d\n", err);
2408+
else
2409+
esw->fdb_table.offloads.drop_root_fc = counter;
2410+
}
2411+
2412+
flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP;
2413+
2414+
if (esw->fdb_table.offloads.drop_root_fc) {
2415+
flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_COUNT;
2416+
drop_fc_dst.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
2417+
drop_fc_dst.counter = esw->fdb_table.offloads.drop_root_fc;
2418+
dst = &drop_fc_dst;
2419+
dst_num++;
2420+
}
2421+
2422+
flow_rule = mlx5_add_flow_rules(table, NULL, &flow_act, dst, dst_num);
2423+
err = PTR_ERR_OR_ZERO(flow_rule);
2424+
if (err) {
2425+
esw_warn(esw->dev,
2426+
"fs offloads: Failed to add vport rx drop rule err %d\n",
2427+
err);
2428+
goto err_flow_rule;
2429+
}
2430+
2431+
esw->fdb_table.offloads.drop_root = table;
2432+
esw->fdb_table.offloads.drop_root_rule = flow_rule;
2433+
esw_debug(esw->dev, "Created FDB drop root table %#x fc %#x\n",
2434+
table->id, dst ? dst->counter->id : 0);
2435+
return 0;
2436+
2437+
err_flow_rule:
2438+
/* no need to free drop fc, esw_offloads_steering_cleanup will do it */
2439+
mlx5_destroy_flow_table(table);
2440+
return err;
2441+
}
2442+
2443+
static void mlx5_esw_fdb_active(struct mlx5_eswitch *esw)
2444+
{
2445+
struct mlx5_vport *vport;
2446+
unsigned long i;
2447+
2448+
mlx5_esw_fdb_drop_destroy(esw);
2449+
mlx5_mpfs_enable(esw->dev);
2450+
2451+
mlx5_esw_for_each_vf_vport(esw, i, vport, U16_MAX) {
2452+
if (!vport->adjacent)
2453+
continue;
2454+
esw_debug(esw->dev, "Connecting vport %d to eswitch\n",
2455+
vport->vport);
2456+
mlx5_esw_adj_vport_modify(esw->dev, vport->vport, true);
2457+
}
2458+
2459+
esw->offloads_inactive = false;
2460+
esw_warn(esw->dev, "MPFS/FDB active\n");
2461+
}
2462+
2463+
static void mlx5_esw_fdb_inactive(struct mlx5_eswitch *esw)
2464+
{
2465+
struct mlx5_vport *vport;
2466+
unsigned long i;
2467+
2468+
mlx5_mpfs_disable(esw->dev);
2469+
mlx5_esw_fdb_drop_create(esw);
2470+
2471+
mlx5_esw_for_each_vf_vport(esw, i, vport, U16_MAX) {
2472+
if (!vport->adjacent)
2473+
continue;
2474+
esw_debug(esw->dev, "Disconnecting vport %u from eswitch\n",
2475+
vport->vport);
2476+
2477+
mlx5_esw_adj_vport_modify(esw->dev, vport->vport, false);
2478+
}
2479+
2480+
esw->offloads_inactive = true;
2481+
esw_warn(esw->dev, "MPFS/FDB inactive\n");
2482+
}
2483+
23582484
static int esw_offloads_start(struct mlx5_eswitch *esw,
23592485
struct netlink_ext_ack *extack)
23602486
{
@@ -3438,6 +3564,10 @@ static int esw_offloads_steering_init(struct mlx5_eswitch *esw)
34383564

34393565
static void esw_offloads_steering_cleanup(struct mlx5_eswitch *esw)
34403566
{
3567+
mlx5_esw_fdb_drop_destroy(esw);
3568+
if (esw->fdb_table.offloads.drop_root_fc)
3569+
mlx5_fc_destroy(esw->dev, esw->fdb_table.offloads.drop_root_fc);
3570+
esw->fdb_table.offloads.drop_root_fc = NULL;
34413571
esw_destroy_vport_rx_drop_rule(esw);
34423572
esw_destroy_vport_rx_drop_group(esw);
34433573
esw_destroy_vport_rx_group(esw);
@@ -3600,6 +3730,11 @@ int esw_offloads_enable(struct mlx5_eswitch *esw)
36003730
if (err)
36013731
goto err_steering_init;
36023732

3733+
if (esw->offloads_inactive)
3734+
mlx5_esw_fdb_inactive(esw);
3735+
else
3736+
mlx5_esw_fdb_active(esw);
3737+
36033738
/* Representor will control the vport link state */
36043739
mlx5_esw_for_each_vf_vport(esw, i, vport, esw->esw_funcs.num_vfs)
36053740
vport->info.link_state = MLX5_VPORT_ADMIN_STATE_DOWN;
@@ -3666,6 +3801,9 @@ void esw_offloads_disable(struct mlx5_eswitch *esw)
36663801
esw_offloads_metadata_uninit(esw);
36673802
mlx5_rdma_disable_roce(esw->dev);
36683803
mlx5_esw_adjacent_vhcas_cleanup(esw);
3804+
/* must be done after vhcas cleanup to avoid adjacent vports connect */
3805+
if (esw->offloads_inactive)
3806+
mlx5_esw_fdb_active(esw); /* legacy mode always active */
36693807
mutex_destroy(&esw->offloads.termtbl_mutex);
36703808
}
36713809

@@ -3676,6 +3814,7 @@ static int esw_mode_from_devlink(u16 mode, u16 *mlx5_mode)
36763814
*mlx5_mode = MLX5_ESWITCH_LEGACY;
36773815
break;
36783816
case DEVLINK_ESWITCH_MODE_SWITCHDEV:
3817+
case DEVLINK_ESWITCH_MODE_SWITCHDEV_INACTIVE:
36793818
*mlx5_mode = MLX5_ESWITCH_OFFLOADS;
36803819
break;
36813820
default:
@@ -3685,14 +3824,17 @@ static int esw_mode_from_devlink(u16 mode, u16 *mlx5_mode)
36853824
return 0;
36863825
}
36873826

3688-
static int esw_mode_to_devlink(u16 mlx5_mode, u16 *mode)
3827+
static int esw_mode_to_devlink(struct mlx5_eswitch *esw, u16 *mode)
36893828
{
3690-
switch (mlx5_mode) {
3829+
switch (esw->mode) {
36913830
case MLX5_ESWITCH_LEGACY:
36923831
*mode = DEVLINK_ESWITCH_MODE_LEGACY;
36933832
break;
36943833
case MLX5_ESWITCH_OFFLOADS:
3695-
*mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
3834+
if (esw->offloads_inactive)
3835+
*mode = DEVLINK_ESWITCH_MODE_SWITCHDEV_INACTIVE;
3836+
else
3837+
*mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
36963838
break;
36973839
default:
36983840
return -EINVAL;
@@ -3798,6 +3940,45 @@ static bool mlx5_devlink_netdev_netns_immutable_set(struct devlink *devlink,
37983940
return ret;
37993941
}
38003942

3943+
/* Returns true when only changing between active and inactive switchdev mode */
3944+
static bool mlx5_devlink_switchdev_active_mode_change(struct mlx5_eswitch *esw,
3945+
u16 devlink_mode)
3946+
{
3947+
/* current mode is not switchdev */
3948+
if (esw->mode != MLX5_ESWITCH_OFFLOADS)
3949+
return false;
3950+
3951+
/* new mode is not switchdev */
3952+
if (devlink_mode != DEVLINK_ESWITCH_MODE_SWITCHDEV &&
3953+
devlink_mode != DEVLINK_ESWITCH_MODE_SWITCHDEV_INACTIVE)
3954+
return false;
3955+
3956+
/* already inactive: no change in current state */
3957+
if (devlink_mode == DEVLINK_ESWITCH_MODE_SWITCHDEV_INACTIVE &&
3958+
esw->offloads_inactive)
3959+
return false;
3960+
3961+
/* already active: no change in current state */
3962+
if (devlink_mode == DEVLINK_ESWITCH_MODE_SWITCHDEV &&
3963+
!esw->offloads_inactive)
3964+
return false;
3965+
3966+
down_write(&esw->mode_lock);
3967+
esw->offloads_inactive = !esw->offloads_inactive;
3968+
esw->eswitch_operation_in_progress = true;
3969+
up_write(&esw->mode_lock);
3970+
3971+
if (esw->offloads_inactive)
3972+
mlx5_esw_fdb_inactive(esw);
3973+
else
3974+
mlx5_esw_fdb_active(esw);
3975+
3976+
down_write(&esw->mode_lock);
3977+
esw->eswitch_operation_in_progress = false;
3978+
up_write(&esw->mode_lock);
3979+
return true;
3980+
}
3981+
38013982
int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
38023983
struct netlink_ext_ack *extack)
38033984
{
@@ -3812,12 +3993,16 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
38123993
if (esw_mode_from_devlink(mode, &mlx5_mode))
38133994
return -EINVAL;
38143995

3815-
if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV && mlx5_get_sd(esw->dev)) {
3996+
if (mlx5_mode == MLX5_ESWITCH_OFFLOADS && mlx5_get_sd(esw->dev)) {
38163997
NL_SET_ERR_MSG_MOD(extack,
38173998
"Can't change E-Switch mode to switchdev when multi-PF netdev (Socket Direct) is configured.");
38183999
return -EPERM;
38194000
}
38204001

4002+
/* Avoid try_lock, active/inactive mode change is not restricted */
4003+
if (mlx5_devlink_switchdev_active_mode_change(esw, mode))
4004+
return 0;
4005+
38214006
mlx5_lag_disable_change(esw->dev);
38224007
err = mlx5_esw_try_lock(esw);
38234008
if (err < 0) {
@@ -3840,33 +4025,35 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
38404025
esw->eswitch_operation_in_progress = true;
38414026
up_write(&esw->mode_lock);
38424027

3843-
if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV &&
4028+
if (mlx5_mode == MLX5_ESWITCH_OFFLOADS &&
38444029
!mlx5_devlink_netdev_netns_immutable_set(devlink, true)) {
38454030
NL_SET_ERR_MSG_MOD(extack,
38464031
"Can't change E-Switch mode to switchdev when netdev net namespace has diverged from the devlink's.");
38474032
err = -EINVAL;
38484033
goto skip;
38494034
}
38504035

3851-
if (mode == DEVLINK_ESWITCH_MODE_LEGACY)
4036+
if (mlx5_mode == MLX5_ESWITCH_LEGACY)
38524037
esw->dev->priv.flags |= MLX5_PRIV_FLAGS_SWITCH_LEGACY;
38534038
mlx5_eswitch_disable_locked(esw);
3854-
if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV) {
4039+
if (mlx5_mode == MLX5_ESWITCH_OFFLOADS) {
38554040
if (mlx5_devlink_trap_get_num_active(esw->dev)) {
38564041
NL_SET_ERR_MSG_MOD(extack,
38574042
"Can't change mode while devlink traps are active");
38584043
err = -EOPNOTSUPP;
38594044
goto skip;
38604045
}
4046+
esw->offloads_inactive =
4047+
(mode == DEVLINK_ESWITCH_MODE_SWITCHDEV_INACTIVE);
38614048
err = esw_offloads_start(esw, extack);
3862-
} else if (mode == DEVLINK_ESWITCH_MODE_LEGACY) {
4049+
} else if (mlx5_mode == MLX5_ESWITCH_LEGACY) {
38634050
err = esw_offloads_stop(esw, extack);
38644051
} else {
38654052
err = -EINVAL;
38664053
}
38674054

38684055
skip:
3869-
if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV && err)
4056+
if (mlx5_mode == MLX5_ESWITCH_OFFLOADS && err)
38704057
mlx5_devlink_netdev_netns_immutable_set(devlink, false);
38714058
down_write(&esw->mode_lock);
38724059
esw->eswitch_operation_in_progress = false;
@@ -3885,7 +4072,7 @@ int mlx5_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
38854072
if (IS_ERR(esw))
38864073
return PTR_ERR(esw);
38874074

3888-
return esw_mode_to_devlink(esw->mode, mode);
4075+
return esw_mode_to_devlink(esw, mode);
38894076
}
38904077

38914078
static int mlx5_esw_vports_inline_set(struct mlx5_eswitch *esw, u8 mlx5_mode,

drivers/net/ethernet/mellanox/mlx5/core/fs_core.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3520,6 +3520,11 @@ static int init_fdb_root_ns(struct mlx5_flow_steering *steering)
35203520
if (!steering->fdb_root_ns)
35213521
return -ENOMEM;
35223522

3523+
maj_prio = fs_create_prio(&steering->fdb_root_ns->ns, FDB_DROP_ROOT, 1);
3524+
err = PTR_ERR_OR_ZERO(maj_prio);
3525+
if (err)
3526+
goto out_err;
3527+
35233528
err = create_fdb_bypass(steering);
35243529
if (err)
35253530
goto out_err;

0 commit comments

Comments
 (0)