@@ -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+
23582484static 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
34393565static 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+
38013982int 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
38684055skip :
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
38914078static int mlx5_esw_vports_inline_set (struct mlx5_eswitch * esw , u8 mlx5_mode ,
0 commit comments