mirror of https://gitee.com/openkylin/linux.git
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>
This commit is contained in:
commit
4ab0edecaf
|
@ -1141,16 +1141,20 @@ static void mlxsw_sp_port_vlan_flush(struct mlxsw_sp_port *mlxsw_sp_port)
|
|||
|
||||
list_for_each_entry_safe(mlxsw_sp_port_vlan, tmp,
|
||||
&mlxsw_sp_port->vlans_list, list)
|
||||
mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan);
|
||||
mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan);
|
||||
}
|
||||
|
||||
static struct mlxsw_sp_port_vlan *
|
||||
struct mlxsw_sp_port_vlan *
|
||||
mlxsw_sp_port_vlan_create(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
|
||||
{
|
||||
struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
|
||||
bool untagged = vid == 1;
|
||||
int err;
|
||||
|
||||
mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
|
||||
if (mlxsw_sp_port_vlan)
|
||||
return ERR_PTR(-EEXIST);
|
||||
|
||||
err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, true, untagged);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
@ -1162,7 +1166,6 @@ mlxsw_sp_port_vlan_create(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
|
|||
}
|
||||
|
||||
mlxsw_sp_port_vlan->mlxsw_sp_port = mlxsw_sp_port;
|
||||
mlxsw_sp_port_vlan->ref_count = 1;
|
||||
mlxsw_sp_port_vlan->vid = vid;
|
||||
list_add(&mlxsw_sp_port_vlan->list, &mlxsw_sp_port->vlans_list);
|
||||
|
||||
|
@ -1173,46 +1176,21 @@ mlxsw_sp_port_vlan_create(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
|
|||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
static void
|
||||
mlxsw_sp_port_vlan_destroy(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
|
||||
void mlxsw_sp_port_vlan_destroy(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
|
||||
{
|
||||
struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
|
||||
u16 vid = mlxsw_sp_port_vlan->vid;
|
||||
|
||||
if (mlxsw_sp_port_vlan->bridge_port)
|
||||
mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan);
|
||||
else if (mlxsw_sp_port_vlan->fid)
|
||||
mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan);
|
||||
|
||||
list_del(&mlxsw_sp_port_vlan->list);
|
||||
kfree(mlxsw_sp_port_vlan);
|
||||
mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, false, false);
|
||||
}
|
||||
|
||||
struct mlxsw_sp_port_vlan *
|
||||
mlxsw_sp_port_vlan_get(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
|
||||
{
|
||||
struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
|
||||
|
||||
mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
|
||||
if (mlxsw_sp_port_vlan) {
|
||||
mlxsw_sp_port_vlan->ref_count++;
|
||||
return mlxsw_sp_port_vlan;
|
||||
}
|
||||
|
||||
return mlxsw_sp_port_vlan_create(mlxsw_sp_port, vid);
|
||||
}
|
||||
|
||||
void mlxsw_sp_port_vlan_put(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
|
||||
{
|
||||
struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
|
||||
|
||||
if (--mlxsw_sp_port_vlan->ref_count != 0)
|
||||
return;
|
||||
|
||||
if (mlxsw_sp_port_vlan->bridge_port)
|
||||
mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan);
|
||||
else if (fid)
|
||||
mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan);
|
||||
|
||||
mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan);
|
||||
}
|
||||
|
||||
static int mlxsw_sp_port_add_vid(struct net_device *dev,
|
||||
__be16 __always_unused proto, u16 vid)
|
||||
{
|
||||
|
@ -1224,7 +1202,7 @@ static int mlxsw_sp_port_add_vid(struct net_device *dev,
|
|||
if (!vid)
|
||||
return 0;
|
||||
|
||||
return PTR_ERR_OR_ZERO(mlxsw_sp_port_vlan_get(mlxsw_sp_port, vid));
|
||||
return PTR_ERR_OR_ZERO(mlxsw_sp_port_vlan_create(mlxsw_sp_port, vid));
|
||||
}
|
||||
|
||||
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,
|
|||
mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
|
||||
if (!mlxsw_sp_port_vlan)
|
||||
return 0;
|
||||
mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan);
|
||||
mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -3198,12 +3176,12 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
|
|||
goto err_port_nve_init;
|
||||
}
|
||||
|
||||
mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_get(mlxsw_sp_port, 1);
|
||||
mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_create(mlxsw_sp_port, 1);
|
||||
if (IS_ERR(mlxsw_sp_port_vlan)) {
|
||||
dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to create VID 1\n",
|
||||
mlxsw_sp_port->local_port);
|
||||
err = PTR_ERR(mlxsw_sp_port_vlan);
|
||||
goto err_port_vlan_get;
|
||||
goto err_port_vlan_create;
|
||||
}
|
||||
|
||||
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,
|
|||
err_register_netdev:
|
||||
mlxsw_sp->ports[local_port] = NULL;
|
||||
mlxsw_sp_port_switchdev_fini(mlxsw_sp_port);
|
||||
mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan);
|
||||
err_port_vlan_get:
|
||||
mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan);
|
||||
err_port_vlan_create:
|
||||
mlxsw_sp_port_nve_fini(mlxsw_sp_port);
|
||||
err_port_nve_init:
|
||||
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)
|
|||
dev_put(mlxsw_sp_port->dev);
|
||||
}
|
||||
|
||||
static void
|
||||
mlxsw_sp_port_lag_uppers_cleanup(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
struct net_device *lag_dev)
|
||||
{
|
||||
struct net_device *br_dev = netdev_master_upper_dev_get(lag_dev);
|
||||
struct net_device *upper_dev;
|
||||
struct list_head *iter;
|
||||
|
||||
if (netif_is_bridge_port(lag_dev))
|
||||
mlxsw_sp_port_bridge_leave(mlxsw_sp_port, lag_dev, br_dev);
|
||||
|
||||
netdev_for_each_upper_dev_rcu(lag_dev, upper_dev, iter) {
|
||||
if (!netif_is_bridge_port(upper_dev))
|
||||
continue;
|
||||
br_dev = netdev_master_upper_dev_get(upper_dev);
|
||||
mlxsw_sp_port_bridge_leave(mlxsw_sp_port, upper_dev, br_dev);
|
||||
}
|
||||
}
|
||||
|
||||
static int mlxsw_sp_lag_create(struct mlxsw_sp *mlxsw_sp, u16 lag_id)
|
||||
{
|
||||
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,
|
|||
|
||||
/* Any VLANs configured on the port are no longer valid */
|
||||
mlxsw_sp_port_vlan_flush(mlxsw_sp_port);
|
||||
/* Make the LAG and its directly linked uppers leave bridges they
|
||||
* are memeber in
|
||||
*/
|
||||
mlxsw_sp_port_lag_uppers_cleanup(mlxsw_sp_port, lag_dev);
|
||||
|
||||
if (lag->ref_count == 1)
|
||||
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,
|
|||
mlxsw_sp_port->lagged = 0;
|
||||
lag->ref_count--;
|
||||
|
||||
mlxsw_sp_port_vlan_get(mlxsw_sp_port, 1);
|
||||
mlxsw_sp_port_vlan_create(mlxsw_sp_port, 1);
|
||||
/* Make sure untagged frames are allowed to ingress */
|
||||
mlxsw_sp_port_pvid_set(mlxsw_sp_port, 1);
|
||||
}
|
||||
|
@ -5000,6 +5001,16 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev,
|
|||
} else if (netif_is_macvlan(upper_dev)) {
|
||||
if (!info->linking)
|
||||
mlxsw_sp_rif_macvlan_del(mlxsw_sp, upper_dev);
|
||||
} else if (is_vlan_dev(upper_dev)) {
|
||||
struct net_device *br_dev;
|
||||
|
||||
if (!netif_is_bridge_port(upper_dev))
|
||||
break;
|
||||
if (info->linking)
|
||||
break;
|
||||
br_dev = netdev_master_upper_dev_get(upper_dev);
|
||||
mlxsw_sp_port_bridge_leave(mlxsw_sp_port, upper_dev,
|
||||
br_dev);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -5156,6 +5167,48 @@ static int mlxsw_sp_netdevice_lag_port_vlan_event(struct net_device *vlan_dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int mlxsw_sp_netdevice_bridge_vlan_event(struct net_device *vlan_dev,
|
||||
struct net_device *br_dev,
|
||||
unsigned long event, void *ptr,
|
||||
u16 vid)
|
||||
{
|
||||
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(vlan_dev);
|
||||
struct netdev_notifier_changeupper_info *info = ptr;
|
||||
struct netlink_ext_ack *extack;
|
||||
struct net_device *upper_dev;
|
||||
|
||||
if (!mlxsw_sp)
|
||||
return 0;
|
||||
|
||||
extack = netdev_notifier_info_to_extack(&info->info);
|
||||
|
||||
switch (event) {
|
||||
case NETDEV_PRECHANGEUPPER:
|
||||
upper_dev = info->upper_dev;
|
||||
if (!netif_is_macvlan(upper_dev)) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
if (!info->linking)
|
||||
break;
|
||||
if (netif_is_macvlan(upper_dev) &&
|
||||
!mlxsw_sp_rif_find_by_dev(mlxsw_sp, vlan_dev)) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "macvlan is only supported on top of router interfaces");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
break;
|
||||
case NETDEV_CHANGEUPPER:
|
||||
upper_dev = info->upper_dev;
|
||||
if (info->linking)
|
||||
break;
|
||||
if (netif_is_macvlan(upper_dev))
|
||||
mlxsw_sp_rif_macvlan_del(mlxsw_sp, upper_dev);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mlxsw_sp_netdevice_vlan_event(struct net_device *vlan_dev,
|
||||
unsigned long event, void *ptr)
|
||||
{
|
||||
|
@ -5169,6 +5222,9 @@ static int mlxsw_sp_netdevice_vlan_event(struct net_device *vlan_dev,
|
|||
return mlxsw_sp_netdevice_lag_port_vlan_event(vlan_dev,
|
||||
real_dev, event,
|
||||
ptr, vid);
|
||||
else if (netif_is_bridge_master(real_dev))
|
||||
return mlxsw_sp_netdevice_bridge_vlan_event(vlan_dev, real_dev,
|
||||
event, ptr, vid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -5358,18 +5414,10 @@ static struct notifier_block mlxsw_sp_inetaddr_valid_nb __read_mostly = {
|
|||
.notifier_call = mlxsw_sp_inetaddr_valid_event,
|
||||
};
|
||||
|
||||
static struct notifier_block mlxsw_sp_inetaddr_nb __read_mostly = {
|
||||
.notifier_call = mlxsw_sp_inetaddr_event,
|
||||
};
|
||||
|
||||
static struct notifier_block mlxsw_sp_inet6addr_valid_nb __read_mostly = {
|
||||
.notifier_call = mlxsw_sp_inet6addr_valid_event,
|
||||
};
|
||||
|
||||
static struct notifier_block mlxsw_sp_inet6addr_nb __read_mostly = {
|
||||
.notifier_call = mlxsw_sp_inet6addr_event,
|
||||
};
|
||||
|
||||
static const struct pci_device_id mlxsw_sp1_pci_id_table[] = {
|
||||
{PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SPECTRUM), 0},
|
||||
{0, },
|
||||
|
@ -5395,9 +5443,7 @@ static int __init mlxsw_sp_module_init(void)
|
|||
int err;
|
||||
|
||||
register_inetaddr_validator_notifier(&mlxsw_sp_inetaddr_valid_nb);
|
||||
register_inetaddr_notifier(&mlxsw_sp_inetaddr_nb);
|
||||
register_inet6addr_validator_notifier(&mlxsw_sp_inet6addr_valid_nb);
|
||||
register_inet6addr_notifier(&mlxsw_sp_inet6addr_nb);
|
||||
|
||||
err = mlxsw_core_driver_register(&mlxsw_sp1_driver);
|
||||
if (err)
|
||||
|
@ -5424,9 +5470,7 @@ static int __init mlxsw_sp_module_init(void)
|
|||
err_sp2_core_driver_register:
|
||||
mlxsw_core_driver_unregister(&mlxsw_sp1_driver);
|
||||
err_sp1_core_driver_register:
|
||||
unregister_inet6addr_notifier(&mlxsw_sp_inet6addr_nb);
|
||||
unregister_inet6addr_validator_notifier(&mlxsw_sp_inet6addr_valid_nb);
|
||||
unregister_inetaddr_notifier(&mlxsw_sp_inetaddr_nb);
|
||||
unregister_inetaddr_validator_notifier(&mlxsw_sp_inetaddr_valid_nb);
|
||||
return err;
|
||||
}
|
||||
|
@ -5437,9 +5481,7 @@ static void __exit mlxsw_sp_module_exit(void)
|
|||
mlxsw_pci_driver_unregister(&mlxsw_sp1_pci_driver);
|
||||
mlxsw_core_driver_unregister(&mlxsw_sp2_driver);
|
||||
mlxsw_core_driver_unregister(&mlxsw_sp1_driver);
|
||||
unregister_inet6addr_notifier(&mlxsw_sp_inet6addr_nb);
|
||||
unregister_inet6addr_validator_notifier(&mlxsw_sp_inet6addr_valid_nb);
|
||||
unregister_inetaddr_notifier(&mlxsw_sp_inetaddr_nb);
|
||||
unregister_inetaddr_validator_notifier(&mlxsw_sp_inetaddr_valid_nb);
|
||||
}
|
||||
|
||||
|
|
|
@ -190,7 +190,6 @@ struct mlxsw_sp_port_vlan {
|
|||
struct list_head list;
|
||||
struct mlxsw_sp_port *mlxsw_sp_port;
|
||||
struct mlxsw_sp_fid *fid;
|
||||
unsigned int ref_count;
|
||||
u16 vid;
|
||||
struct mlxsw_sp_bridge_port *bridge_port;
|
||||
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,
|
|||
bool learn_enable);
|
||||
int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid);
|
||||
struct mlxsw_sp_port_vlan *
|
||||
mlxsw_sp_port_vlan_get(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid);
|
||||
void mlxsw_sp_port_vlan_put(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan);
|
||||
mlxsw_sp_port_vlan_create(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid);
|
||||
void mlxsw_sp_port_vlan_destroy(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan);
|
||||
int mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid_begin,
|
||||
u16 vid_end, bool is_member, bool untagged);
|
||||
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,
|
|||
unsigned long event, void *ptr);
|
||||
void mlxsw_sp_rif_macvlan_del(struct mlxsw_sp *mlxsw_sp,
|
||||
const struct net_device *macvlan_dev);
|
||||
int mlxsw_sp_inetaddr_event(struct notifier_block *unused,
|
||||
unsigned long event, void *ptr);
|
||||
int mlxsw_sp_inetaddr_valid_event(struct notifier_block *unused,
|
||||
unsigned long event, void *ptr);
|
||||
int mlxsw_sp_inet6addr_event(struct notifier_block *unused,
|
||||
unsigned long event, void *ptr);
|
||||
int mlxsw_sp_inet6addr_valid_event(struct notifier_block *unused,
|
||||
unsigned long event, void *ptr);
|
||||
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,
|
|||
struct netdev_notifier_info *info);
|
||||
void
|
||||
mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan);
|
||||
void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif);
|
||||
void mlxsw_sp_rif_destroy_by_dev(struct mlxsw_sp *mlxsw_sp,
|
||||
struct net_device *dev);
|
||||
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,
|
|||
struct mlxsw_sp_port *mlxsw_sp_port, u16 vid);
|
||||
void mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid *fid,
|
||||
struct mlxsw_sp_port *mlxsw_sp_port, u16 vid);
|
||||
enum mlxsw_sp_rif_type mlxsw_sp_fid_rif_type(const struct mlxsw_sp_fid *fid);
|
||||
u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid);
|
||||
enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid);
|
||||
void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif);
|
||||
struct mlxsw_sp_rif *mlxsw_sp_fid_rif(const struct mlxsw_sp_fid *fid);
|
||||
enum mlxsw_sp_rif_type
|
||||
mlxsw_sp_fid_type_rif_type(const struct mlxsw_sp *mlxsw_sp,
|
||||
enum mlxsw_sp_fid_type type);
|
||||
|
|
|
@ -349,11 +349,6 @@ void mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid *fid,
|
|||
fid->fid_family->ops->port_vid_unmap(fid, mlxsw_sp_port, vid);
|
||||
}
|
||||
|
||||
enum mlxsw_sp_rif_type mlxsw_sp_fid_rif_type(const struct mlxsw_sp_fid *fid)
|
||||
{
|
||||
return fid->fid_family->rif_type;
|
||||
}
|
||||
|
||||
u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid)
|
||||
{
|
||||
return fid->fid_index;
|
||||
|
@ -369,6 +364,11 @@ void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif)
|
|||
fid->rif = rif;
|
||||
}
|
||||
|
||||
struct mlxsw_sp_rif *mlxsw_sp_fid_rif(const struct mlxsw_sp_fid *fid)
|
||||
{
|
||||
return fid->rif;
|
||||
}
|
||||
|
||||
enum mlxsw_sp_rif_type
|
||||
mlxsw_sp_fid_type_rif_type(const struct mlxsw_sp *mlxsw_sp,
|
||||
enum mlxsw_sp_fid_type type)
|
||||
|
@ -1083,20 +1083,16 @@ void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid)
|
|||
struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
|
||||
struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
|
||||
|
||||
if (--fid->ref_count == 1 && fid->rif) {
|
||||
/* Destroy the associated RIF and let it drop the last
|
||||
* reference on the FID.
|
||||
*/
|
||||
return mlxsw_sp_rif_destroy(fid->rif);
|
||||
} else if (fid->ref_count == 0) {
|
||||
list_del(&fid->list);
|
||||
rhashtable_remove_fast(&mlxsw_sp->fid_core->fid_ht,
|
||||
&fid->ht_node, mlxsw_sp_fid_ht_params);
|
||||
fid->fid_family->ops->deconfigure(fid);
|
||||
__clear_bit(fid->fid_index - fid_family->start_index,
|
||||
fid_family->fids_bitmap);
|
||||
kfree(fid);
|
||||
}
|
||||
if (--fid->ref_count != 0)
|
||||
return;
|
||||
|
||||
list_del(&fid->list);
|
||||
rhashtable_remove_fast(&mlxsw_sp->fid_core->fid_ht,
|
||||
&fid->ht_node, mlxsw_sp_fid_ht_params);
|
||||
fid->fid_family->ops->deconfigure(fid);
|
||||
__clear_bit(fid->fid_index - fid_family->start_index,
|
||||
fid_family->fids_bitmap);
|
||||
kfree(fid);
|
||||
}
|
||||
|
||||
struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid)
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <linux/gcd.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/if_macvlan.h>
|
||||
#include <linux/refcount.h>
|
||||
#include <net/netevent.h>
|
||||
#include <net/neighbour.h>
|
||||
#include <net/arp.h>
|
||||
|
@ -70,6 +71,8 @@ struct mlxsw_sp_router {
|
|||
bool aborted;
|
||||
struct notifier_block fib_nb;
|
||||
struct notifier_block netevent_nb;
|
||||
struct notifier_block inetaddr_nb;
|
||||
struct notifier_block inet6addr_nb;
|
||||
const struct mlxsw_sp_rif_ops **rif_ops_arr;
|
||||
const struct mlxsw_sp_ipip_ops **ipip_ops_arr;
|
||||
};
|
||||
|
@ -104,6 +107,7 @@ struct mlxsw_sp_rif_params {
|
|||
|
||||
struct mlxsw_sp_rif_subport {
|
||||
struct mlxsw_sp_rif common;
|
||||
refcount_t ref_count;
|
||||
union {
|
||||
u16 system_port;
|
||||
u16 lag_id;
|
||||
|
@ -136,6 +140,7 @@ struct mlxsw_sp_rif_ops {
|
|||
void (*fdb_del)(struct mlxsw_sp_rif *rif, const char *mac);
|
||||
};
|
||||
|
||||
static void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif);
|
||||
static void mlxsw_sp_lpm_tree_hold(struct mlxsw_sp_lpm_tree *lpm_tree);
|
||||
static void mlxsw_sp_lpm_tree_put(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_lpm_tree *lpm_tree);
|
||||
|
@ -6297,6 +6302,7 @@ mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp,
|
|||
err = -ENOMEM;
|
||||
goto err_rif_alloc;
|
||||
}
|
||||
dev_hold(rif->dev);
|
||||
rif->mlxsw_sp = mlxsw_sp;
|
||||
rif->ops = ops;
|
||||
|
||||
|
@ -6335,6 +6341,7 @@ mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp,
|
|||
if (fid)
|
||||
mlxsw_sp_fid_put(fid);
|
||||
err_fid_get:
|
||||
dev_put(rif->dev);
|
||||
kfree(rif);
|
||||
err_rif_alloc:
|
||||
err_rif_index_alloc:
|
||||
|
@ -6343,7 +6350,7 @@ mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp,
|
|||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif)
|
||||
static void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif)
|
||||
{
|
||||
const struct mlxsw_sp_rif_ops *ops = rif->ops;
|
||||
struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
|
||||
|
@ -6362,6 +6369,7 @@ void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif)
|
|||
if (fid)
|
||||
/* Loopback RIFs are not associated with a FID. */
|
||||
mlxsw_sp_fid_put(fid);
|
||||
dev_put(rif->dev);
|
||||
kfree(rif);
|
||||
vr->rif_count--;
|
||||
mlxsw_sp_vr_put(mlxsw_sp, vr);
|
||||
|
@ -6392,6 +6400,40 @@ mlxsw_sp_rif_subport_params_init(struct mlxsw_sp_rif_params *params,
|
|||
params->system_port = mlxsw_sp_port->local_port;
|
||||
}
|
||||
|
||||
static struct mlxsw_sp_rif_subport *
|
||||
mlxsw_sp_rif_subport_rif(const struct mlxsw_sp_rif *rif)
|
||||
{
|
||||
return container_of(rif, struct mlxsw_sp_rif_subport, common);
|
||||
}
|
||||
|
||||
static struct mlxsw_sp_rif *
|
||||
mlxsw_sp_rif_subport_get(struct mlxsw_sp *mlxsw_sp,
|
||||
const struct mlxsw_sp_rif_params *params,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct mlxsw_sp_rif_subport *rif_subport;
|
||||
struct mlxsw_sp_rif *rif;
|
||||
|
||||
rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, params->dev);
|
||||
if (!rif)
|
||||
return mlxsw_sp_rif_create(mlxsw_sp, params, extack);
|
||||
|
||||
rif_subport = mlxsw_sp_rif_subport_rif(rif);
|
||||
refcount_inc(&rif_subport->ref_count);
|
||||
return rif;
|
||||
}
|
||||
|
||||
static void mlxsw_sp_rif_subport_put(struct mlxsw_sp_rif *rif)
|
||||
{
|
||||
struct mlxsw_sp_rif_subport *rif_subport;
|
||||
|
||||
rif_subport = mlxsw_sp_rif_subport_rif(rif);
|
||||
if (!refcount_dec_and_test(&rif_subport->ref_count))
|
||||
return;
|
||||
|
||||
mlxsw_sp_rif_destroy(rif);
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_sp_port_vlan_router_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
|
||||
struct net_device *l3_dev,
|
||||
|
@ -6399,22 +6441,18 @@ mlxsw_sp_port_vlan_router_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
|
|||
{
|
||||
struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
|
||||
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
|
||||
struct mlxsw_sp_rif_params params = {
|
||||
.dev = l3_dev,
|
||||
};
|
||||
u16 vid = mlxsw_sp_port_vlan->vid;
|
||||
struct mlxsw_sp_rif *rif;
|
||||
struct mlxsw_sp_fid *fid;
|
||||
int err;
|
||||
|
||||
rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev);
|
||||
if (!rif) {
|
||||
struct mlxsw_sp_rif_params params = {
|
||||
.dev = l3_dev,
|
||||
};
|
||||
|
||||
mlxsw_sp_rif_subport_params_init(¶ms, mlxsw_sp_port_vlan);
|
||||
rif = mlxsw_sp_rif_create(mlxsw_sp, ¶ms, extack);
|
||||
if (IS_ERR(rif))
|
||||
return PTR_ERR(rif);
|
||||
}
|
||||
mlxsw_sp_rif_subport_params_init(¶ms, mlxsw_sp_port_vlan);
|
||||
rif = mlxsw_sp_rif_subport_get(mlxsw_sp, ¶ms, extack);
|
||||
if (IS_ERR(rif))
|
||||
return PTR_ERR(rif);
|
||||
|
||||
/* FID was already created, just take a reference */
|
||||
fid = rif->ops->fid_get(rif, extack);
|
||||
|
@ -6441,6 +6479,7 @@ mlxsw_sp_port_vlan_router_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
|
|||
mlxsw_sp_fid_port_vid_unmap(fid, mlxsw_sp_port, vid);
|
||||
err_fid_port_vid_map:
|
||||
mlxsw_sp_fid_put(fid);
|
||||
mlxsw_sp_rif_subport_put(rif);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -6449,6 +6488,7 @@ mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
|
|||
{
|
||||
struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
|
||||
struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
|
||||
struct mlxsw_sp_rif *rif = mlxsw_sp_fid_rif(fid);
|
||||
u16 vid = mlxsw_sp_port_vlan->vid;
|
||||
|
||||
if (WARN_ON(mlxsw_sp_fid_type(fid) != MLXSW_SP_FID_TYPE_RFID))
|
||||
|
@ -6458,10 +6498,8 @@ mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
|
|||
mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, BR_STATE_BLOCKING);
|
||||
mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, true);
|
||||
mlxsw_sp_fid_port_vid_unmap(fid, mlxsw_sp_port, vid);
|
||||
/* If router port holds the last reference on the rFID, then the
|
||||
* associated Sub-port RIF will be destroyed.
|
||||
*/
|
||||
mlxsw_sp_fid_put(fid);
|
||||
mlxsw_sp_rif_subport_put(rif);
|
||||
}
|
||||
|
||||
static int mlxsw_sp_inetaddr_port_vlan_event(struct net_device *l3_dev,
|
||||
|
@ -6535,11 +6573,11 @@ static int mlxsw_sp_inetaddr_lag_event(struct net_device *lag_dev,
|
|||
extack);
|
||||
}
|
||||
|
||||
static int mlxsw_sp_inetaddr_bridge_event(struct net_device *l3_dev,
|
||||
static int mlxsw_sp_inetaddr_bridge_event(struct mlxsw_sp *mlxsw_sp,
|
||||
struct net_device *l3_dev,
|
||||
unsigned long event,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(l3_dev);
|
||||
struct mlxsw_sp_rif_params params = {
|
||||
.dev = l3_dev,
|
||||
};
|
||||
|
@ -6560,7 +6598,8 @@ static int mlxsw_sp_inetaddr_bridge_event(struct net_device *l3_dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int mlxsw_sp_inetaddr_vlan_event(struct net_device *vlan_dev,
|
||||
static int mlxsw_sp_inetaddr_vlan_event(struct mlxsw_sp *mlxsw_sp,
|
||||
struct net_device *vlan_dev,
|
||||
unsigned long event,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
|
@ -6577,7 +6616,8 @@ static int mlxsw_sp_inetaddr_vlan_event(struct net_device *vlan_dev,
|
|||
return __mlxsw_sp_inetaddr_lag_event(vlan_dev, real_dev, event,
|
||||
vid, extack);
|
||||
else if (netif_is_bridge_master(real_dev) && br_vlan_enabled(real_dev))
|
||||
return mlxsw_sp_inetaddr_bridge_event(vlan_dev, event, extack);
|
||||
return mlxsw_sp_inetaddr_bridge_event(mlxsw_sp, vlan_dev, event,
|
||||
extack);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -6678,16 +6718,11 @@ void mlxsw_sp_rif_macvlan_del(struct mlxsw_sp *mlxsw_sp,
|
|||
mlxsw_sp_fid_index(rif->fid), false);
|
||||
}
|
||||
|
||||
static int mlxsw_sp_inetaddr_macvlan_event(struct net_device *macvlan_dev,
|
||||
static int mlxsw_sp_inetaddr_macvlan_event(struct mlxsw_sp *mlxsw_sp,
|
||||
struct net_device *macvlan_dev,
|
||||
unsigned long event,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct mlxsw_sp *mlxsw_sp;
|
||||
|
||||
mlxsw_sp = mlxsw_sp_lower_get(macvlan_dev);
|
||||
if (!mlxsw_sp)
|
||||
return 0;
|
||||
|
||||
switch (event) {
|
||||
case NETDEV_UP:
|
||||
return mlxsw_sp_rif_macvlan_add(mlxsw_sp, macvlan_dev, extack);
|
||||
|
@ -6726,7 +6761,8 @@ static int mlxsw_sp_router_port_check_rif_addr(struct mlxsw_sp *mlxsw_sp,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __mlxsw_sp_inetaddr_event(struct net_device *dev,
|
||||
static int __mlxsw_sp_inetaddr_event(struct mlxsw_sp *mlxsw_sp,
|
||||
struct net_device *dev,
|
||||
unsigned long event,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
|
@ -6735,21 +6771,24 @@ static int __mlxsw_sp_inetaddr_event(struct net_device *dev,
|
|||
else if (netif_is_lag_master(dev))
|
||||
return mlxsw_sp_inetaddr_lag_event(dev, event, extack);
|
||||
else if (netif_is_bridge_master(dev))
|
||||
return mlxsw_sp_inetaddr_bridge_event(dev, event, extack);
|
||||
return mlxsw_sp_inetaddr_bridge_event(mlxsw_sp, dev, event,
|
||||
extack);
|
||||
else if (is_vlan_dev(dev))
|
||||
return mlxsw_sp_inetaddr_vlan_event(dev, event, extack);
|
||||
return mlxsw_sp_inetaddr_vlan_event(mlxsw_sp, dev, event,
|
||||
extack);
|
||||
else if (netif_is_macvlan(dev))
|
||||
return mlxsw_sp_inetaddr_macvlan_event(dev, event, extack);
|
||||
return mlxsw_sp_inetaddr_macvlan_event(mlxsw_sp, dev, event,
|
||||
extack);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mlxsw_sp_inetaddr_event(struct notifier_block *unused,
|
||||
unsigned long event, void *ptr)
|
||||
static int mlxsw_sp_inetaddr_event(struct notifier_block *nb,
|
||||
unsigned long event, void *ptr)
|
||||
{
|
||||
struct in_ifaddr *ifa = (struct in_ifaddr *) ptr;
|
||||
struct net_device *dev = ifa->ifa_dev->dev;
|
||||
struct mlxsw_sp *mlxsw_sp;
|
||||
struct mlxsw_sp_router *router;
|
||||
struct mlxsw_sp_rif *rif;
|
||||
int err = 0;
|
||||
|
||||
|
@ -6757,15 +6796,12 @@ int mlxsw_sp_inetaddr_event(struct notifier_block *unused,
|
|||
if (event == NETDEV_UP)
|
||||
goto out;
|
||||
|
||||
mlxsw_sp = mlxsw_sp_lower_get(dev);
|
||||
if (!mlxsw_sp)
|
||||
goto out;
|
||||
|
||||
rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
|
||||
router = container_of(nb, struct mlxsw_sp_router, inetaddr_nb);
|
||||
rif = mlxsw_sp_rif_find_by_dev(router->mlxsw_sp, dev);
|
||||
if (!mlxsw_sp_rif_should_config(rif, dev, event))
|
||||
goto out;
|
||||
|
||||
err = __mlxsw_sp_inetaddr_event(dev, event, NULL);
|
||||
err = __mlxsw_sp_inetaddr_event(router->mlxsw_sp, dev, event, NULL);
|
||||
out:
|
||||
return notifier_from_errno(err);
|
||||
}
|
||||
|
@ -6792,13 +6828,14 @@ int mlxsw_sp_inetaddr_valid_event(struct notifier_block *unused,
|
|||
if (err)
|
||||
goto out;
|
||||
|
||||
err = __mlxsw_sp_inetaddr_event(dev, event, ivi->extack);
|
||||
err = __mlxsw_sp_inetaddr_event(mlxsw_sp, dev, event, ivi->extack);
|
||||
out:
|
||||
return notifier_from_errno(err);
|
||||
}
|
||||
|
||||
struct mlxsw_sp_inet6addr_event_work {
|
||||
struct work_struct work;
|
||||
struct mlxsw_sp *mlxsw_sp;
|
||||
struct net_device *dev;
|
||||
unsigned long event;
|
||||
};
|
||||
|
@ -6807,21 +6844,18 @@ static void mlxsw_sp_inet6addr_event_work(struct work_struct *work)
|
|||
{
|
||||
struct mlxsw_sp_inet6addr_event_work *inet6addr_work =
|
||||
container_of(work, struct mlxsw_sp_inet6addr_event_work, work);
|
||||
struct mlxsw_sp *mlxsw_sp = inet6addr_work->mlxsw_sp;
|
||||
struct net_device *dev = inet6addr_work->dev;
|
||||
unsigned long event = inet6addr_work->event;
|
||||
struct mlxsw_sp *mlxsw_sp;
|
||||
struct mlxsw_sp_rif *rif;
|
||||
|
||||
rtnl_lock();
|
||||
mlxsw_sp = mlxsw_sp_lower_get(dev);
|
||||
if (!mlxsw_sp)
|
||||
goto out;
|
||||
|
||||
rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
|
||||
if (!mlxsw_sp_rif_should_config(rif, dev, event))
|
||||
goto out;
|
||||
|
||||
__mlxsw_sp_inetaddr_event(dev, event, NULL);
|
||||
__mlxsw_sp_inetaddr_event(mlxsw_sp, dev, event, NULL);
|
||||
out:
|
||||
rtnl_unlock();
|
||||
dev_put(dev);
|
||||
|
@ -6829,25 +6863,25 @@ static void mlxsw_sp_inet6addr_event_work(struct work_struct *work)
|
|||
}
|
||||
|
||||
/* Called with rcu_read_lock() */
|
||||
int mlxsw_sp_inet6addr_event(struct notifier_block *unused,
|
||||
unsigned long event, void *ptr)
|
||||
static int mlxsw_sp_inet6addr_event(struct notifier_block *nb,
|
||||
unsigned long event, void *ptr)
|
||||
{
|
||||
struct inet6_ifaddr *if6 = (struct inet6_ifaddr *) ptr;
|
||||
struct mlxsw_sp_inet6addr_event_work *inet6addr_work;
|
||||
struct net_device *dev = if6->idev->dev;
|
||||
struct mlxsw_sp_router *router;
|
||||
|
||||
/* NETDEV_UP event is handled by mlxsw_sp_inet6addr_valid_event */
|
||||
if (event == NETDEV_UP)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
if (!mlxsw_sp_port_dev_lower_find_rcu(dev))
|
||||
return NOTIFY_DONE;
|
||||
|
||||
inet6addr_work = kzalloc(sizeof(*inet6addr_work), GFP_ATOMIC);
|
||||
if (!inet6addr_work)
|
||||
return NOTIFY_BAD;
|
||||
|
||||
router = container_of(nb, struct mlxsw_sp_router, inet6addr_nb);
|
||||
INIT_WORK(&inet6addr_work->work, mlxsw_sp_inet6addr_event_work);
|
||||
inet6addr_work->mlxsw_sp = router->mlxsw_sp;
|
||||
inet6addr_work->dev = dev;
|
||||
inet6addr_work->event = event;
|
||||
dev_hold(dev);
|
||||
|
@ -6878,7 +6912,7 @@ int mlxsw_sp_inet6addr_valid_event(struct notifier_block *unused,
|
|||
if (err)
|
||||
goto out;
|
||||
|
||||
err = __mlxsw_sp_inetaddr_event(dev, event, i6vi->extack);
|
||||
err = __mlxsw_sp_inetaddr_event(mlxsw_sp, dev, event, i6vi->extack);
|
||||
out:
|
||||
return notifier_from_errno(err);
|
||||
}
|
||||
|
@ -6997,9 +7031,10 @@ static int mlxsw_sp_port_vrf_join(struct mlxsw_sp *mlxsw_sp,
|
|||
*/
|
||||
rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev);
|
||||
if (rif)
|
||||
__mlxsw_sp_inetaddr_event(l3_dev, NETDEV_DOWN, extack);
|
||||
__mlxsw_sp_inetaddr_event(mlxsw_sp, l3_dev, NETDEV_DOWN,
|
||||
extack);
|
||||
|
||||
return __mlxsw_sp_inetaddr_event(l3_dev, NETDEV_UP, extack);
|
||||
return __mlxsw_sp_inetaddr_event(mlxsw_sp, l3_dev, NETDEV_UP, extack);
|
||||
}
|
||||
|
||||
static void mlxsw_sp_port_vrf_leave(struct mlxsw_sp *mlxsw_sp,
|
||||
|
@ -7010,7 +7045,7 @@ static void mlxsw_sp_port_vrf_leave(struct mlxsw_sp *mlxsw_sp,
|
|||
rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev);
|
||||
if (!rif)
|
||||
return;
|
||||
__mlxsw_sp_inetaddr_event(l3_dev, NETDEV_DOWN, NULL);
|
||||
__mlxsw_sp_inetaddr_event(mlxsw_sp, l3_dev, NETDEV_DOWN, NULL);
|
||||
}
|
||||
|
||||
int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event,
|
||||
|
@ -7064,18 +7099,13 @@ static int mlxsw_sp_rif_macvlan_flush(struct mlxsw_sp_rif *rif)
|
|||
__mlxsw_sp_rif_macvlan_flush, rif);
|
||||
}
|
||||
|
||||
static struct mlxsw_sp_rif_subport *
|
||||
mlxsw_sp_rif_subport_rif(const struct mlxsw_sp_rif *rif)
|
||||
{
|
||||
return container_of(rif, struct mlxsw_sp_rif_subport, common);
|
||||
}
|
||||
|
||||
static void mlxsw_sp_rif_subport_setup(struct mlxsw_sp_rif *rif,
|
||||
const struct mlxsw_sp_rif_params *params)
|
||||
{
|
||||
struct mlxsw_sp_rif_subport *rif_subport;
|
||||
|
||||
rif_subport = mlxsw_sp_rif_subport_rif(rif);
|
||||
refcount_set(&rif_subport->ref_count, 1);
|
||||
rif_subport->vid = params->vid;
|
||||
rif_subport->lag = params->lag;
|
||||
if (params->lag)
|
||||
|
@ -7627,6 +7657,16 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
|
|||
mlxsw_sp->router = router;
|
||||
router->mlxsw_sp = mlxsw_sp;
|
||||
|
||||
router->inetaddr_nb.notifier_call = mlxsw_sp_inetaddr_event;
|
||||
err = register_inetaddr_notifier(&router->inetaddr_nb);
|
||||
if (err)
|
||||
goto err_register_inetaddr_notifier;
|
||||
|
||||
router->inet6addr_nb.notifier_call = mlxsw_sp_inet6addr_event;
|
||||
err = register_inet6addr_notifier(&router->inet6addr_nb);
|
||||
if (err)
|
||||
goto err_register_inet6addr_notifier;
|
||||
|
||||
INIT_LIST_HEAD(&mlxsw_sp->router->nexthop_neighs_list);
|
||||
err = __mlxsw_sp_router_init(mlxsw_sp);
|
||||
if (err)
|
||||
|
@ -7712,6 +7752,10 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
|
|||
err_rifs_init:
|
||||
__mlxsw_sp_router_fini(mlxsw_sp);
|
||||
err_router_init:
|
||||
unregister_inet6addr_notifier(&router->inet6addr_nb);
|
||||
err_register_inet6addr_notifier:
|
||||
unregister_inetaddr_notifier(&router->inetaddr_nb);
|
||||
err_register_inetaddr_notifier:
|
||||
kfree(mlxsw_sp->router);
|
||||
return err;
|
||||
}
|
||||
|
@ -7729,5 +7773,7 @@ void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
|
|||
mlxsw_sp_ipips_fini(mlxsw_sp);
|
||||
mlxsw_sp_rifs_fini(mlxsw_sp);
|
||||
__mlxsw_sp_router_fini(mlxsw_sp);
|
||||
unregister_inet6addr_notifier(&mlxsw_sp->router->inet6addr_nb);
|
||||
unregister_inetaddr_notifier(&mlxsw_sp->router->inetaddr_nb);
|
||||
kfree(mlxsw_sp->router);
|
||||
}
|
||||
|
|
|
@ -290,30 +290,6 @@ mlxsw_sp_bridge_port_destroy(struct mlxsw_sp_bridge_port *bridge_port)
|
|||
kfree(bridge_port);
|
||||
}
|
||||
|
||||
static bool
|
||||
mlxsw_sp_bridge_port_should_destroy(const struct mlxsw_sp_bridge_port *
|
||||
bridge_port)
|
||||
{
|
||||
struct net_device *dev = bridge_port->dev;
|
||||
struct mlxsw_sp *mlxsw_sp;
|
||||
|
||||
if (is_vlan_dev(dev))
|
||||
mlxsw_sp = mlxsw_sp_lower_get(vlan_dev_real_dev(dev));
|
||||
else
|
||||
mlxsw_sp = mlxsw_sp_lower_get(dev);
|
||||
|
||||
/* In case ports were pulled from out of a bridged LAG, then
|
||||
* it's possible the reference count isn't zero, yet the bridge
|
||||
* port should be destroyed, as it's no longer an upper of ours.
|
||||
*/
|
||||
if (!mlxsw_sp && list_empty(&bridge_port->vlans_list))
|
||||
return true;
|
||||
else if (bridge_port->ref_count == 0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct mlxsw_sp_bridge_port *
|
||||
mlxsw_sp_bridge_port_get(struct mlxsw_sp_bridge *bridge,
|
||||
struct net_device *brport_dev)
|
||||
|
@ -351,8 +327,7 @@ static void mlxsw_sp_bridge_port_put(struct mlxsw_sp_bridge *bridge,
|
|||
{
|
||||
struct mlxsw_sp_bridge_device *bridge_device;
|
||||
|
||||
bridge_port->ref_count--;
|
||||
if (!mlxsw_sp_bridge_port_should_destroy(bridge_port))
|
||||
if (--bridge_port->ref_count != 0)
|
||||
return;
|
||||
bridge_device = bridge_port->bridge_device;
|
||||
mlxsw_sp_bridge_port_destroy(bridge_port);
|
||||
|
@ -1021,10 +996,8 @@ mlxsw_sp_port_vlan_bridge_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
|
|||
int err;
|
||||
|
||||
/* No need to continue if only VLAN flags were changed */
|
||||
if (mlxsw_sp_port_vlan->bridge_port) {
|
||||
mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan);
|
||||
if (mlxsw_sp_port_vlan->bridge_port)
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = mlxsw_sp_port_vlan_fid_join(mlxsw_sp_port_vlan, bridge_port,
|
||||
extack);
|
||||
|
@ -1105,16 +1078,32 @@ static int
|
|||
mlxsw_sp_bridge_port_vlan_add(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
struct mlxsw_sp_bridge_port *bridge_port,
|
||||
u16 vid, bool is_untagged, bool is_pvid,
|
||||
struct netlink_ext_ack *extack)
|
||||
struct netlink_ext_ack *extack,
|
||||
struct switchdev_trans *trans)
|
||||
{
|
||||
u16 pvid = mlxsw_sp_port_pvid_determine(mlxsw_sp_port, vid, is_pvid);
|
||||
struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
|
||||
u16 old_pvid = mlxsw_sp_port->pvid;
|
||||
int err;
|
||||
|
||||
mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_get(mlxsw_sp_port, vid);
|
||||
if (IS_ERR(mlxsw_sp_port_vlan))
|
||||
return PTR_ERR(mlxsw_sp_port_vlan);
|
||||
/* The only valid scenario in which a port-vlan already exists, is if
|
||||
* the VLAN flags were changed and the port-vlan is associated with the
|
||||
* correct bridge port
|
||||
*/
|
||||
mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
|
||||
if (mlxsw_sp_port_vlan &&
|
||||
mlxsw_sp_port_vlan->bridge_port != bridge_port)
|
||||
return -EEXIST;
|
||||
|
||||
if (switchdev_trans_ph_prepare(trans))
|
||||
return 0;
|
||||
|
||||
if (!mlxsw_sp_port_vlan) {
|
||||
mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_create(mlxsw_sp_port,
|
||||
vid);
|
||||
if (IS_ERR(mlxsw_sp_port_vlan))
|
||||
return PTR_ERR(mlxsw_sp_port_vlan);
|
||||
}
|
||||
|
||||
err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, true,
|
||||
is_untagged);
|
||||
|
@ -1137,7 +1126,7 @@ mlxsw_sp_bridge_port_vlan_add(struct mlxsw_sp_port *mlxsw_sp_port,
|
|||
err_port_pvid_set:
|
||||
mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, false, false);
|
||||
err_port_vlan_set:
|
||||
mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan);
|
||||
mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -1199,9 +1188,6 @@ static int mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port,
|
|||
return err;
|
||||
}
|
||||
|
||||
if (switchdev_trans_ph_prepare(trans))
|
||||
return 0;
|
||||
|
||||
bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev);
|
||||
if (WARN_ON(!bridge_port))
|
||||
return -EINVAL;
|
||||
|
@ -1214,7 +1200,7 @@ static int mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port,
|
|||
|
||||
err = mlxsw_sp_bridge_port_vlan_add(mlxsw_sp_port, bridge_port,
|
||||
vid, flag_untagged,
|
||||
flag_pvid, extack);
|
||||
flag_pvid, extack, trans);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
@ -1832,7 +1818,7 @@ mlxsw_sp_bridge_port_vlan_del(struct mlxsw_sp_port *mlxsw_sp_port,
|
|||
mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan);
|
||||
mlxsw_sp_port_pvid_set(mlxsw_sp_port, pvid);
|
||||
mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, false, false);
|
||||
mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan);
|
||||
mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan);
|
||||
}
|
||||
|
||||
static int mlxsw_sp_port_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
|
@ -2000,7 +1986,7 @@ mlxsw_sp_bridge_8021q_port_join(struct mlxsw_sp_bridge_device *bridge_device,
|
|||
return -EINVAL;
|
||||
|
||||
/* Let VLAN-aware bridge take care of its own VLANs */
|
||||
mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan);
|
||||
mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2010,7 +1996,7 @@ mlxsw_sp_bridge_8021q_port_leave(struct mlxsw_sp_bridge_device *bridge_device,
|
|||
struct mlxsw_sp_bridge_port *bridge_port,
|
||||
struct mlxsw_sp_port *mlxsw_sp_port)
|
||||
{
|
||||
mlxsw_sp_port_vlan_get(mlxsw_sp_port, 1);
|
||||
mlxsw_sp_port_vlan_create(mlxsw_sp_port, 1);
|
||||
/* Make sure untagged frames are allowed to ingress */
|
||||
mlxsw_sp_port_pvid_set(mlxsw_sp_port, 1);
|
||||
}
|
||||
|
|
|
@ -13,9 +13,23 @@ ALL_TESTS="
|
|||
rif_set_addr_test
|
||||
rif_inherit_bridge_addr_test
|
||||
rif_non_inherit_bridge_addr_test
|
||||
vlan_interface_deletion_test
|
||||
bridge_deletion_test
|
||||
bridge_vlan_flags_test
|
||||
vlan_1_test
|
||||
lag_bridge_upper_test
|
||||
duplicate_vlans_test
|
||||
vlan_rif_refcount_test
|
||||
subport_rif_refcount_test
|
||||
vlan_dev_deletion_test
|
||||
lag_unlink_slaves_test
|
||||
lag_dev_deletion_test
|
||||
vlan_interface_uppers_test
|
||||
devlink_reload_test
|
||||
"
|
||||
NUM_NETIFS=2
|
||||
source $lib_dir/lib.sh
|
||||
source $lib_dir/devlink_lib.sh
|
||||
|
||||
setup_prepare()
|
||||
{
|
||||
|
@ -160,6 +174,384 @@ rif_non_inherit_bridge_addr_test()
|
|||
ip addr del dev $swp1 192.0.2.1/28
|
||||
}
|
||||
|
||||
vlan_interface_deletion_test()
|
||||
{
|
||||
# Test that when a VLAN interface is deleted, its associated router
|
||||
# interface (RIF) is correctly deleted and not leaked. See commit
|
||||
# c360867ec46a ("mlxsw: spectrum: Delete RIF when VLAN device is
|
||||
# removed") for more details
|
||||
RET=0
|
||||
|
||||
ip link add name br0 type bridge vlan_filtering 1
|
||||
ip link set dev $swp1 master br0
|
||||
|
||||
ip link add link br0 name br0.10 type vlan id 10
|
||||
ip -6 address add 2001:db8:1::1/64 dev br0.10
|
||||
ip link del dev br0.10
|
||||
|
||||
# If we leaked the previous RIF, then this should produce a trace
|
||||
ip link add link br0 name br0.20 type vlan id 20
|
||||
ip -6 address add 2001:db8:1::1/64 dev br0.20
|
||||
ip link del dev br0.20
|
||||
|
||||
log_test "vlan interface deletion"
|
||||
|
||||
ip link del dev br0
|
||||
}
|
||||
|
||||
bridge_deletion_test()
|
||||
{
|
||||
# Test that when a bridge with VLAN interfaces is deleted, we correctly
|
||||
# delete the associated RIFs. See commit 602b74eda813 ("mlxsw:
|
||||
# spectrum_switchdev: Do not leak RIFs when removing bridge") for more
|
||||
# details
|
||||
RET=0
|
||||
|
||||
ip link add name br0 type bridge vlan_filtering 1
|
||||
ip link set dev $swp1 master br0
|
||||
ip -6 address add 2001:db8::1/64 dev br0
|
||||
|
||||
ip link add link br0 name br0.10 type vlan id 10
|
||||
ip -6 address add 2001:db8:1::1/64 dev br0.10
|
||||
|
||||
ip link add link br0 name br0.20 type vlan id 20
|
||||
ip -6 address add 2001:db8:2::1/64 dev br0.20
|
||||
|
||||
ip link del dev br0
|
||||
|
||||
# If we leaked previous RIFs, then this should produce a trace
|
||||
ip -6 address add 2001:db8:1::1/64 dev $swp1
|
||||
ip -6 address del 2001:db8:1::1/64 dev $swp1
|
||||
|
||||
log_test "bridge deletion"
|
||||
}
|
||||
|
||||
bridge_vlan_flags_test()
|
||||
{
|
||||
# Test that when bridge VLAN flags are toggled, we do not take
|
||||
# unnecessary references on related structs. See commit 9e25826ffc94
|
||||
# ("mlxsw: spectrum_switchdev: Fix port_vlan refcounting") for more
|
||||
# details
|
||||
RET=0
|
||||
|
||||
ip link add name br0 type bridge vlan_filtering 1
|
||||
ip link set dev $swp1 master br0
|
||||
|
||||
bridge vlan add vid 10 dev $swp1 pvid untagged
|
||||
bridge vlan add vid 10 dev $swp1 untagged
|
||||
bridge vlan add vid 10 dev $swp1 pvid
|
||||
bridge vlan add vid 10 dev $swp1
|
||||
ip link del dev br0
|
||||
|
||||
# If we did not handle references correctly, then this should produce a
|
||||
# trace
|
||||
devlink dev reload "$DEVLINK_DEV"
|
||||
|
||||
# Allow netdevices to be re-created following the reload
|
||||
sleep 20
|
||||
|
||||
log_test "bridge vlan flags"
|
||||
}
|
||||
|
||||
vlan_1_test()
|
||||
{
|
||||
# Test that VLAN 1 cannot be configured, as it is used internally for
|
||||
# untagged traffic. See commit 47bf9df2e820 ("mlxsw: spectrum: Forbid
|
||||
# creation of VLAN 1 over port/LAG") for more details
|
||||
RET=0
|
||||
|
||||
ip link add link $swp1 name $swp1.1 type vlan id 1 &> /dev/null
|
||||
check_fail $? "managed to create vlan 1 when should not"
|
||||
|
||||
log_test "vlan 1"
|
||||
}
|
||||
|
||||
lag_bridge_upper_test()
|
||||
{
|
||||
# Test that ports cannot be enslaved to LAG devices that have uppers
|
||||
# and that failure is handled gracefully. See commit b3529af6bb0d
|
||||
# ("spectrum: Reference count VLAN entries") for more details
|
||||
RET=0
|
||||
|
||||
ip link add name bond1 type bond mode 802.3ad
|
||||
|
||||
ip link add name br0 type bridge vlan_filtering 1
|
||||
ip link set dev bond1 master br0
|
||||
|
||||
ip link set dev $swp1 down
|
||||
ip link set dev $swp1 master bond1 &> /dev/null
|
||||
check_fail $? "managed to enslave port to lag when should not"
|
||||
|
||||
# This might generate a trace, if we did not handle the failure
|
||||
# correctly
|
||||
ip -6 address add 2001:db8:1::1/64 dev $swp1
|
||||
ip -6 address del 2001:db8:1::1/64 dev $swp1
|
||||
|
||||
log_test "lag with bridge upper"
|
||||
|
||||
ip link del dev br0
|
||||
ip link del dev bond1
|
||||
}
|
||||
|
||||
duplicate_vlans_test()
|
||||
{
|
||||
# Test that on a given port a VLAN is only used once. Either as VLAN
|
||||
# in a VLAN-aware bridge or as a VLAN device
|
||||
RET=0
|
||||
|
||||
ip link add name br0 type bridge vlan_filtering 1
|
||||
ip link set dev $swp1 master br0
|
||||
bridge vlan add vid 10 dev $swp1
|
||||
|
||||
ip link add link $swp1 name $swp1.10 type vlan id 10 &> /dev/null
|
||||
check_fail $? "managed to create vlan device when should not"
|
||||
|
||||
bridge vlan del vid 10 dev $swp1
|
||||
ip link add link $swp1 name $swp1.10 type vlan id 10
|
||||
check_err $? "did not manage to create vlan device when should"
|
||||
bridge vlan add vid 10 dev $swp1 &> /dev/null
|
||||
check_fail $? "managed to add bridge vlan when should not"
|
||||
|
||||
log_test "duplicate vlans"
|
||||
|
||||
ip link del dev $swp1.10
|
||||
ip link del dev br0
|
||||
}
|
||||
|
||||
vlan_rif_refcount_test()
|
||||
{
|
||||
# Test that RIFs representing VLAN interfaces are not affected from
|
||||
# ports member in the VLAN. We use the offload indication on routes
|
||||
# configured on the RIF to understand if it was created / destroyed
|
||||
RET=0
|
||||
|
||||
ip link add name br0 type bridge vlan_filtering 1
|
||||
ip link set dev $swp1 master br0
|
||||
|
||||
ip link set dev $swp1 up
|
||||
ip link set dev br0 up
|
||||
|
||||
ip link add link br0 name br0.10 up type vlan id 10
|
||||
ip -6 address add 2001:db8:1::1/64 dev br0.10
|
||||
|
||||
ip -6 route get fibmatch 2001:db8:1::2 dev br0.10 | grep -q offload
|
||||
check_err $? "vlan rif was not created before adding port to vlan"
|
||||
|
||||
bridge vlan add vid 10 dev $swp1
|
||||
ip -6 route get fibmatch 2001:db8:1::2 dev br0.10 | grep -q offload
|
||||
check_err $? "vlan rif was destroyed after adding port to vlan"
|
||||
|
||||
bridge vlan del vid 10 dev $swp1
|
||||
ip -6 route get fibmatch 2001:db8:1::2 dev br0.10 | grep -q offload
|
||||
check_err $? "vlan rif was destroyed after removing port from vlan"
|
||||
|
||||
ip link set dev $swp1 nomaster
|
||||
ip -6 route get fibmatch 2001:db8:1::2 dev br0.10 | grep -q offload
|
||||
check_fail $? "vlan rif was not destroyed after unlinking port from bridge"
|
||||
|
||||
log_test "vlan rif refcount"
|
||||
|
||||
ip link del dev br0.10
|
||||
ip link set dev $swp1 down
|
||||
ip link del dev br0
|
||||
}
|
||||
|
||||
subport_rif_refcount_test()
|
||||
{
|
||||
# Test that RIFs representing upper devices of physical ports are
|
||||
# reference counted correctly and destroyed when should. We use the
|
||||
# offload indication on routes configured on the RIF to understand if
|
||||
# it was created / destroyed
|
||||
RET=0
|
||||
|
||||
ip link add name bond1 type bond mode 802.3ad
|
||||
ip link set dev $swp1 down
|
||||
ip link set dev $swp2 down
|
||||
ip link set dev $swp1 master bond1
|
||||
ip link set dev $swp2 master bond1
|
||||
|
||||
ip link set dev bond1 up
|
||||
ip link add link bond1 name bond1.10 up type vlan id 10
|
||||
ip -6 address add 2001:db8:1::1/64 dev bond1
|
||||
ip -6 address add 2001:db8:2::1/64 dev bond1.10
|
||||
|
||||
ip -6 route get fibmatch 2001:db8:1::2 dev bond1 | grep -q offload
|
||||
check_err $? "subport rif was not created on lag device"
|
||||
ip -6 route get fibmatch 2001:db8:2::2 dev bond1.10 | grep -q offload
|
||||
check_err $? "subport rif was not created on vlan device"
|
||||
|
||||
ip link set dev $swp1 nomaster
|
||||
ip -6 route get fibmatch 2001:db8:1::2 dev bond1 | grep -q offload
|
||||
check_err $? "subport rif of lag device was destroyed when should not"
|
||||
ip -6 route get fibmatch 2001:db8:2::2 dev bond1.10 | grep -q offload
|
||||
check_err $? "subport rif of vlan device was destroyed when should not"
|
||||
|
||||
ip link set dev $swp2 nomaster
|
||||
ip -6 route get fibmatch 2001:db8:1::2 dev bond1 | grep -q offload
|
||||
check_fail $? "subport rif of lag device was not destroyed when should"
|
||||
ip -6 route get fibmatch 2001:db8:2::2 dev bond1.10 | grep -q offload
|
||||
check_fail $? "subport rif of vlan device was not destroyed when should"
|
||||
|
||||
log_test "subport rif refcount"
|
||||
|
||||
ip link del dev bond1.10
|
||||
ip link del dev bond1
|
||||
}
|
||||
|
||||
vlan_dev_deletion_test()
|
||||
{
|
||||
# Test that VLAN devices are correctly deleted / unlinked when enslaved
|
||||
# to bridge
|
||||
RET=0
|
||||
|
||||
ip link add name br10 type bridge
|
||||
ip link add name br20 type bridge
|
||||
ip link add name br30 type bridge
|
||||
ip link add link $swp1 name $swp1.10 type vlan id 10
|
||||
ip link add link $swp1 name $swp1.20 type vlan id 20
|
||||
ip link add link $swp1 name $swp1.30 type vlan id 30
|
||||
ip link set dev $swp1.10 master br10
|
||||
ip link set dev $swp1.20 master br20
|
||||
ip link set dev $swp1.30 master br30
|
||||
|
||||
# If we did not handle the situation correctly, then these operations
|
||||
# might produce a trace
|
||||
ip link set dev $swp1.30 nomaster
|
||||
ip link del dev $swp1.20
|
||||
# Deletion via ioctl uses different code paths from netlink
|
||||
vconfig rem $swp1.10 &> /dev/null
|
||||
|
||||
log_test "vlan device deletion"
|
||||
|
||||
ip link del dev $swp1.30
|
||||
ip link del dev br30
|
||||
ip link del dev br20
|
||||
ip link del dev br10
|
||||
}
|
||||
|
||||
lag_create()
|
||||
{
|
||||
ip link add name bond1 type bond mode 802.3ad
|
||||
ip link set dev $swp1 down
|
||||
ip link set dev $swp2 down
|
||||
ip link set dev $swp1 master bond1
|
||||
ip link set dev $swp2 master bond1
|
||||
|
||||
ip link add link bond1 name bond1.10 type vlan id 10
|
||||
ip link add link bond1 name bond1.20 type vlan id 20
|
||||
|
||||
ip link add name br0 type bridge vlan_filtering 1
|
||||
ip link set dev bond1 master br0
|
||||
|
||||
ip link add name br10 type bridge
|
||||
ip link set dev bond1.10 master br10
|
||||
|
||||
ip link add name br20 type bridge
|
||||
ip link set dev bond1.20 master br20
|
||||
}
|
||||
|
||||
lag_unlink_slaves_test()
|
||||
{
|
||||
# Test that ports are correctly unlinked from their LAG master, when
|
||||
# the LAG and its VLAN uppers are enslaved to bridges
|
||||
RET=0
|
||||
|
||||
lag_create
|
||||
|
||||
ip link set dev $swp1 nomaster
|
||||
check_err $? "lag slave $swp1 was not unlinked from master"
|
||||
ip link set dev $swp2 nomaster
|
||||
check_err $? "lag slave $swp2 was not unlinked from master"
|
||||
|
||||
# Try to configure corresponding VLANs as router interfaces
|
||||
ip -6 address add 2001:db8:1::1/64 dev $swp1
|
||||
check_err $? "failed to configure ip address on $swp1"
|
||||
|
||||
ip link add link $swp1 name $swp1.10 type vlan id 10
|
||||
ip -6 address add 2001:db8:10::1/64 dev $swp1.10
|
||||
check_err $? "failed to configure ip address on $swp1.10"
|
||||
|
||||
ip link add link $swp1 name $swp1.20 type vlan id 20
|
||||
ip -6 address add 2001:db8:20::1/64 dev $swp1.20
|
||||
check_err $? "failed to configure ip address on $swp1.20"
|
||||
|
||||
log_test "lag slaves unlinking"
|
||||
|
||||
ip link del dev $swp1.20
|
||||
ip link del dev $swp1.10
|
||||
ip address flush dev $swp1
|
||||
|
||||
ip link del dev br20
|
||||
ip link del dev br10
|
||||
ip link del dev br0
|
||||
ip link del dev bond1
|
||||
}
|
||||
|
||||
lag_dev_deletion_test()
|
||||
{
|
||||
# Test that LAG device is correctly deleted, when the LAG and its VLAN
|
||||
# uppers are enslaved to bridges
|
||||
RET=0
|
||||
|
||||
lag_create
|
||||
|
||||
ip link del dev bond1
|
||||
|
||||
log_test "lag device deletion"
|
||||
|
||||
ip link del dev br20
|
||||
ip link del dev br10
|
||||
ip link del dev br0
|
||||
}
|
||||
|
||||
vlan_interface_uppers_test()
|
||||
{
|
||||
# Test that uppers of a VLAN interface are correctly sanitized
|
||||
RET=0
|
||||
|
||||
ip link add name br0 type bridge vlan_filtering 1
|
||||
ip link set dev $swp1 master br0
|
||||
|
||||
ip link add link br0 name br0.10 type vlan id 10
|
||||
ip link add link br0.10 name macvlan0 \
|
||||
type macvlan mode private &> /dev/null
|
||||
check_fail $? "managed to create a macvlan when should not"
|
||||
|
||||
ip -6 address add 2001:db8:1::1/64 dev br0.10
|
||||
ip link add link br0.10 name macvlan0 type macvlan mode private
|
||||
check_err $? "did not manage to create a macvlan when should"
|
||||
|
||||
ip link del dev macvlan0
|
||||
|
||||
ip link add name vrf-test type vrf table 10
|
||||
ip link set dev br0.10 master vrf-test
|
||||
check_err $? "did not manage to enslave vlan interface to vrf"
|
||||
ip link del dev vrf-test
|
||||
|
||||
ip link add name br-test type bridge
|
||||
ip link set dev br0.10 master br-test &> /dev/null
|
||||
check_fail $? "managed to enslave vlan interface to bridge when should not"
|
||||
ip link del dev br-test
|
||||
|
||||
log_test "vlan interface uppers"
|
||||
|
||||
ip link del dev br0
|
||||
}
|
||||
|
||||
devlink_reload_test()
|
||||
{
|
||||
# Test that after executing all the above configuration tests, a
|
||||
# devlink reload can be performed without errors
|
||||
RET=0
|
||||
|
||||
devlink dev reload "$DEVLINK_DEV"
|
||||
check_err $? "devlink reload failed"
|
||||
|
||||
log_test "devlink reload - last test"
|
||||
|
||||
sleep 20
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
setup_prepare
|
||||
|
|
Loading…
Reference in New Issue