Skip to content

Commit 4ab0ede

Browse files
committed
Merge branch 'mlxsw-Make-driver-more-robust'
Ido Schimmel says: ==================== mlxsw: Make driver more robust In recent months we fixed several bugs in the driver that could have been avoided by re-evaluating some of the involved code paths and by introducing relevant and comprehensive test cases. This patchset tries to do that by introducing a set of small and mostly non-functional changes in addition to a new test. I have further improvements in mind, but they can be done in a different set. Patch #1 makes sure we correctly sanitize upper devices of a VLAN interface. Patch #2 removes an unexpected behavior from the driver, in which routes configured on a VLAN interface will cease being offloaded after certain operations. Patch #3 is a small cleanup. Patch #4 simplifies the driver by removing reference counting from VLAN entries configured on a port. Patches #5-#6 simplify linking/unlinking from a bridge, especially when LAG and VLAN devices are involved. They make both operations symmetric even when ports are unlinked from a bridged LAG device. Patch #7-#9 make router interface (RIF) deletion more robust by removing reliance on device chain to indicate whether a NETDEV_DOWN event in the inet{,6}addr notification chains should be processed. This is due to the fact that IP addresses can be flushed from a netdev after it was unlinked from its lower device. Patch #10 adds a new test to for valid and invalid configurations over mlxsw ports. Some of the test cases are derived from recent fixes. I expect that more test cases will be added over time. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
2 parents 0557227 + 489c25f commit 4ab0ede

File tree

6 files changed

+639
-183
lines changed

6 files changed

+639
-183
lines changed

drivers/net/ethernet/mellanox/mlxsw/spectrum.c

+96-54
Original file line numberDiff line numberDiff line change
@@ -1141,16 +1141,20 @@ static void mlxsw_sp_port_vlan_flush(struct mlxsw_sp_port *mlxsw_sp_port)
11411141

11421142
list_for_each_entry_safe(mlxsw_sp_port_vlan, tmp,
11431143
&mlxsw_sp_port->vlans_list, list)
1144-
mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan);
1144+
mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan);
11451145
}
11461146

1147-
static struct mlxsw_sp_port_vlan *
1147+
struct mlxsw_sp_port_vlan *
11481148
mlxsw_sp_port_vlan_create(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
11491149
{
11501150
struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
11511151
bool untagged = vid == 1;
11521152
int err;
11531153

1154+
mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
1155+
if (mlxsw_sp_port_vlan)
1156+
return ERR_PTR(-EEXIST);
1157+
11541158
err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, true, untagged);
11551159
if (err)
11561160
return ERR_PTR(err);
@@ -1162,7 +1166,6 @@ mlxsw_sp_port_vlan_create(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
11621166
}
11631167

11641168
mlxsw_sp_port_vlan->mlxsw_sp_port = mlxsw_sp_port;
1165-
mlxsw_sp_port_vlan->ref_count = 1;
11661169
mlxsw_sp_port_vlan->vid = vid;
11671170
list_add(&mlxsw_sp_port_vlan->list, &mlxsw_sp_port->vlans_list);
11681171

@@ -1173,44 +1176,19 @@ mlxsw_sp_port_vlan_create(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
11731176
return ERR_PTR(err);
11741177
}
11751178

1176-
static void
1177-
mlxsw_sp_port_vlan_destroy(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
1179+
void mlxsw_sp_port_vlan_destroy(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
11781180
{
11791181
struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
11801182
u16 vid = mlxsw_sp_port_vlan->vid;
11811183

1182-
list_del(&mlxsw_sp_port_vlan->list);
1183-
kfree(mlxsw_sp_port_vlan);
1184-
mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, false, false);
1185-
}
1186-
1187-
struct mlxsw_sp_port_vlan *
1188-
mlxsw_sp_port_vlan_get(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
1189-
{
1190-
struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
1191-
1192-
mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
1193-
if (mlxsw_sp_port_vlan) {
1194-
mlxsw_sp_port_vlan->ref_count++;
1195-
return mlxsw_sp_port_vlan;
1196-
}
1197-
1198-
return mlxsw_sp_port_vlan_create(mlxsw_sp_port, vid);
1199-
}
1200-
1201-
void mlxsw_sp_port_vlan_put(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
1202-
{
1203-
struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
1204-
1205-
if (--mlxsw_sp_port_vlan->ref_count != 0)
1206-
return;
1207-
12081184
if (mlxsw_sp_port_vlan->bridge_port)
12091185
mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan);
1210-
else if (fid)
1186+
else if (mlxsw_sp_port_vlan->fid)
12111187
mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan);
12121188

1213-
mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan);
1189+
list_del(&mlxsw_sp_port_vlan->list);
1190+
kfree(mlxsw_sp_port_vlan);
1191+
mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, false, false);
12141192
}
12151193

12161194
static int mlxsw_sp_port_add_vid(struct net_device *dev,
@@ -1224,7 +1202,7 @@ static int mlxsw_sp_port_add_vid(struct net_device *dev,
12241202
if (!vid)
12251203
return 0;
12261204

1227-
return PTR_ERR_OR_ZERO(mlxsw_sp_port_vlan_get(mlxsw_sp_port, vid));
1205+
return PTR_ERR_OR_ZERO(mlxsw_sp_port_vlan_create(mlxsw_sp_port, vid));
12281206
}
12291207

12301208
static int mlxsw_sp_port_kill_vid(struct net_device *dev,
@@ -1242,7 +1220,7 @@ static int mlxsw_sp_port_kill_vid(struct net_device *dev,
12421220
mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
12431221
if (!mlxsw_sp_port_vlan)
12441222
return 0;
1245-
mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan);
1223+
mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan);
12461224

12471225
return 0;
12481226
}
@@ -3198,12 +3176,12 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
31983176
goto err_port_nve_init;
31993177
}
32003178

3201-
mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_get(mlxsw_sp_port, 1);
3179+
mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_create(mlxsw_sp_port, 1);
32023180
if (IS_ERR(mlxsw_sp_port_vlan)) {
32033181
dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to create VID 1\n",
32043182
mlxsw_sp_port->local_port);
32053183
err = PTR_ERR(mlxsw_sp_port_vlan);
3206-
goto err_port_vlan_get;
3184+
goto err_port_vlan_create;
32073185
}
32083186

32093187
mlxsw_sp_port_switchdev_init(mlxsw_sp_port);
@@ -3224,8 +3202,8 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
32243202
err_register_netdev:
32253203
mlxsw_sp->ports[local_port] = NULL;
32263204
mlxsw_sp_port_switchdev_fini(mlxsw_sp_port);
3227-
mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan);
3228-
err_port_vlan_get:
3205+
mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan);
3206+
err_port_vlan_create:
32293207
mlxsw_sp_port_nve_fini(mlxsw_sp_port);
32303208
err_port_nve_init:
32313209
mlxsw_sp_tc_qdisc_fini(mlxsw_sp_port);
@@ -4520,6 +4498,25 @@ void mlxsw_sp_port_dev_put(struct mlxsw_sp_port *mlxsw_sp_port)
45204498
dev_put(mlxsw_sp_port->dev);
45214499
}
45224500

4501+
static void
4502+
mlxsw_sp_port_lag_uppers_cleanup(struct mlxsw_sp_port *mlxsw_sp_port,
4503+
struct net_device *lag_dev)
4504+
{
4505+
struct net_device *br_dev = netdev_master_upper_dev_get(lag_dev);
4506+
struct net_device *upper_dev;
4507+
struct list_head *iter;
4508+
4509+
if (netif_is_bridge_port(lag_dev))
4510+
mlxsw_sp_port_bridge_leave(mlxsw_sp_port, lag_dev, br_dev);
4511+
4512+
netdev_for_each_upper_dev_rcu(lag_dev, upper_dev, iter) {
4513+
if (!netif_is_bridge_port(upper_dev))
4514+
continue;
4515+
br_dev = netdev_master_upper_dev_get(upper_dev);
4516+
mlxsw_sp_port_bridge_leave(mlxsw_sp_port, upper_dev, br_dev);
4517+
}
4518+
}
4519+
45234520
static int mlxsw_sp_lag_create(struct mlxsw_sp *mlxsw_sp, u16 lag_id)
45244521
{
45254522
char sldr_pl[MLXSW_REG_SLDR_LEN];
@@ -4712,6 +4709,10 @@ static void mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port,
47124709

47134710
/* Any VLANs configured on the port are no longer valid */
47144711
mlxsw_sp_port_vlan_flush(mlxsw_sp_port);
4712+
/* Make the LAG and its directly linked uppers leave bridges they
4713+
* are memeber in
4714+
*/
4715+
mlxsw_sp_port_lag_uppers_cleanup(mlxsw_sp_port, lag_dev);
47154716

47164717
if (lag->ref_count == 1)
47174718
mlxsw_sp_lag_destroy(mlxsw_sp, lag_id);
@@ -4721,7 +4722,7 @@ static void mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port,
47214722
mlxsw_sp_port->lagged = 0;
47224723
lag->ref_count--;
47234724

4724-
mlxsw_sp_port_vlan_get(mlxsw_sp_port, 1);
4725+
mlxsw_sp_port_vlan_create(mlxsw_sp_port, 1);
47254726
/* Make sure untagged frames are allowed to ingress */
47264727
mlxsw_sp_port_pvid_set(mlxsw_sp_port, 1);
47274728
}
@@ -5000,6 +5001,16 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev,
50005001
} else if (netif_is_macvlan(upper_dev)) {
50015002
if (!info->linking)
50025003
mlxsw_sp_rif_macvlan_del(mlxsw_sp, upper_dev);
5004+
} else if (is_vlan_dev(upper_dev)) {
5005+
struct net_device *br_dev;
5006+
5007+
if (!netif_is_bridge_port(upper_dev))
5008+
break;
5009+
if (info->linking)
5010+
break;
5011+
br_dev = netdev_master_upper_dev_get(upper_dev);
5012+
mlxsw_sp_port_bridge_leave(mlxsw_sp_port, upper_dev,
5013+
br_dev);
50035014
}
50045015
break;
50055016
}
@@ -5156,6 +5167,48 @@ static int mlxsw_sp_netdevice_lag_port_vlan_event(struct net_device *vlan_dev,
51565167
return 0;
51575168
}
51585169

5170+
static int mlxsw_sp_netdevice_bridge_vlan_event(struct net_device *vlan_dev,
5171+
struct net_device *br_dev,
5172+
unsigned long event, void *ptr,
5173+
u16 vid)
5174+
{
5175+
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(vlan_dev);
5176+
struct netdev_notifier_changeupper_info *info = ptr;
5177+
struct netlink_ext_ack *extack;
5178+
struct net_device *upper_dev;
5179+
5180+
if (!mlxsw_sp)
5181+
return 0;
5182+
5183+
extack = netdev_notifier_info_to_extack(&info->info);
5184+
5185+
switch (event) {
5186+
case NETDEV_PRECHANGEUPPER:
5187+
upper_dev = info->upper_dev;
5188+
if (!netif_is_macvlan(upper_dev)) {
5189+
NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type");
5190+
return -EOPNOTSUPP;
5191+
}
5192+
if (!info->linking)
5193+
break;
5194+
if (netif_is_macvlan(upper_dev) &&
5195+
!mlxsw_sp_rif_find_by_dev(mlxsw_sp, vlan_dev)) {
5196+
NL_SET_ERR_MSG_MOD(extack, "macvlan is only supported on top of router interfaces");
5197+
return -EOPNOTSUPP;
5198+
}
5199+
break;
5200+
case NETDEV_CHANGEUPPER:
5201+
upper_dev = info->upper_dev;
5202+
if (info->linking)
5203+
break;
5204+
if (netif_is_macvlan(upper_dev))
5205+
mlxsw_sp_rif_macvlan_del(mlxsw_sp, upper_dev);
5206+
break;
5207+
}
5208+
5209+
return 0;
5210+
}
5211+
51595212
static int mlxsw_sp_netdevice_vlan_event(struct net_device *vlan_dev,
51605213
unsigned long event, void *ptr)
51615214
{
@@ -5169,6 +5222,9 @@ static int mlxsw_sp_netdevice_vlan_event(struct net_device *vlan_dev,
51695222
return mlxsw_sp_netdevice_lag_port_vlan_event(vlan_dev,
51705223
real_dev, event,
51715224
ptr, vid);
5225+
else if (netif_is_bridge_master(real_dev))
5226+
return mlxsw_sp_netdevice_bridge_vlan_event(vlan_dev, real_dev,
5227+
event, ptr, vid);
51725228

51735229
return 0;
51745230
}
@@ -5358,18 +5414,10 @@ static struct notifier_block mlxsw_sp_inetaddr_valid_nb __read_mostly = {
53585414
.notifier_call = mlxsw_sp_inetaddr_valid_event,
53595415
};
53605416

5361-
static struct notifier_block mlxsw_sp_inetaddr_nb __read_mostly = {
5362-
.notifier_call = mlxsw_sp_inetaddr_event,
5363-
};
5364-
53655417
static struct notifier_block mlxsw_sp_inet6addr_valid_nb __read_mostly = {
53665418
.notifier_call = mlxsw_sp_inet6addr_valid_event,
53675419
};
53685420

5369-
static struct notifier_block mlxsw_sp_inet6addr_nb __read_mostly = {
5370-
.notifier_call = mlxsw_sp_inet6addr_event,
5371-
};
5372-
53735421
static const struct pci_device_id mlxsw_sp1_pci_id_table[] = {
53745422
{PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SPECTRUM), 0},
53755423
{0, },
@@ -5395,9 +5443,7 @@ static int __init mlxsw_sp_module_init(void)
53955443
int err;
53965444

53975445
register_inetaddr_validator_notifier(&mlxsw_sp_inetaddr_valid_nb);
5398-
register_inetaddr_notifier(&mlxsw_sp_inetaddr_nb);
53995446
register_inet6addr_validator_notifier(&mlxsw_sp_inet6addr_valid_nb);
5400-
register_inet6addr_notifier(&mlxsw_sp_inet6addr_nb);
54015447

54025448
err = mlxsw_core_driver_register(&mlxsw_sp1_driver);
54035449
if (err)
@@ -5424,9 +5470,7 @@ static int __init mlxsw_sp_module_init(void)
54245470
err_sp2_core_driver_register:
54255471
mlxsw_core_driver_unregister(&mlxsw_sp1_driver);
54265472
err_sp1_core_driver_register:
5427-
unregister_inet6addr_notifier(&mlxsw_sp_inet6addr_nb);
54285473
unregister_inet6addr_validator_notifier(&mlxsw_sp_inet6addr_valid_nb);
5429-
unregister_inetaddr_notifier(&mlxsw_sp_inetaddr_nb);
54305474
unregister_inetaddr_validator_notifier(&mlxsw_sp_inetaddr_valid_nb);
54315475
return err;
54325476
}
@@ -5437,9 +5481,7 @@ static void __exit mlxsw_sp_module_exit(void)
54375481
mlxsw_pci_driver_unregister(&mlxsw_sp1_pci_driver);
54385482
mlxsw_core_driver_unregister(&mlxsw_sp2_driver);
54395483
mlxsw_core_driver_unregister(&mlxsw_sp1_driver);
5440-
unregister_inet6addr_notifier(&mlxsw_sp_inet6addr_nb);
54415484
unregister_inet6addr_validator_notifier(&mlxsw_sp_inet6addr_valid_nb);
5442-
unregister_inetaddr_notifier(&mlxsw_sp_inetaddr_nb);
54435485
unregister_inetaddr_validator_notifier(&mlxsw_sp_inetaddr_valid_nb);
54445486
}
54455487

drivers/net/ethernet/mellanox/mlxsw/spectrum.h

+3-9
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,6 @@ struct mlxsw_sp_port_vlan {
190190
struct list_head list;
191191
struct mlxsw_sp_port *mlxsw_sp_port;
192192
struct mlxsw_sp_fid *fid;
193-
unsigned int ref_count;
194193
u16 vid;
195194
struct mlxsw_sp_bridge_port *bridge_port;
196195
struct list_head bridge_vlan_node;
@@ -410,8 +409,8 @@ int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid,
410409
bool learn_enable);
411410
int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid);
412411
struct mlxsw_sp_port_vlan *
413-
mlxsw_sp_port_vlan_get(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid);
414-
void mlxsw_sp_port_vlan_put(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan);
412+
mlxsw_sp_port_vlan_create(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid);
413+
void mlxsw_sp_port_vlan_destroy(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan);
415414
int mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid_begin,
416415
u16 vid_end, bool is_member, bool untagged);
417416
int mlxsw_sp_flow_counter_get(struct mlxsw_sp *mlxsw_sp,
@@ -459,12 +458,8 @@ int mlxsw_sp_netdevice_router_port_event(struct net_device *dev,
459458
unsigned long event, void *ptr);
460459
void mlxsw_sp_rif_macvlan_del(struct mlxsw_sp *mlxsw_sp,
461460
const struct net_device *macvlan_dev);
462-
int mlxsw_sp_inetaddr_event(struct notifier_block *unused,
463-
unsigned long event, void *ptr);
464461
int mlxsw_sp_inetaddr_valid_event(struct notifier_block *unused,
465462
unsigned long event, void *ptr);
466-
int mlxsw_sp_inet6addr_event(struct notifier_block *unused,
467-
unsigned long event, void *ptr);
468463
int mlxsw_sp_inet6addr_valid_event(struct notifier_block *unused,
469464
unsigned long event, void *ptr);
470465
int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event,
@@ -484,7 +479,6 @@ mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp *mlxsw_sp,
484479
struct netdev_notifier_info *info);
485480
void
486481
mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan);
487-
void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif);
488482
void mlxsw_sp_rif_destroy_by_dev(struct mlxsw_sp *mlxsw_sp,
489483
struct net_device *dev);
490484
struct mlxsw_sp_rif *mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp,
@@ -785,10 +779,10 @@ int mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid *fid,
785779
struct mlxsw_sp_port *mlxsw_sp_port, u16 vid);
786780
void mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid *fid,
787781
struct mlxsw_sp_port *mlxsw_sp_port, u16 vid);
788-
enum mlxsw_sp_rif_type mlxsw_sp_fid_rif_type(const struct mlxsw_sp_fid *fid);
789782
u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid);
790783
enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid);
791784
void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif);
785+
struct mlxsw_sp_rif *mlxsw_sp_fid_rif(const struct mlxsw_sp_fid *fid);
792786
enum mlxsw_sp_rif_type
793787
mlxsw_sp_fid_type_rif_type(const struct mlxsw_sp *mlxsw_sp,
794788
enum mlxsw_sp_fid_type type);

0 commit comments

Comments
 (0)