mirror of
https://github.com/torvalds/linux.git
synced 2024-11-28 07:01:32 +00:00
Merge branch 'enslavement-extack'
David Ahern says: ==================== net: Plumb extack error reporting to enslavements Another round of extending extack error reporting, this time for enslavements through ndo_add_slave and notifiers. v2 - changed how the messages are added to bonding driver per Jiri's request - fixed spectrum message for LAG overflow per Ido's comment ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
c331501c88
@ -1217,14 +1217,15 @@ static enum netdev_lag_tx_type bond_lag_tx_type(struct bonding *bond)
|
||||
}
|
||||
}
|
||||
|
||||
static int bond_master_upper_dev_link(struct bonding *bond, struct slave *slave)
|
||||
static int bond_master_upper_dev_link(struct bonding *bond, struct slave *slave,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct netdev_lag_upper_info lag_upper_info;
|
||||
int err;
|
||||
|
||||
lag_upper_info.tx_type = bond_lag_tx_type(bond);
|
||||
err = netdev_master_upper_dev_link(slave->dev, bond->dev, slave,
|
||||
&lag_upper_info);
|
||||
&lag_upper_info, extack);
|
||||
if (err)
|
||||
return err;
|
||||
rtmsg_ifinfo(RTM_NEWLINK, slave->dev, IFF_SLAVE, GFP_KERNEL);
|
||||
@ -1328,7 +1329,8 @@ void bond_lower_state_changed(struct slave *slave)
|
||||
}
|
||||
|
||||
/* enslave device <slave> to bond device <master> */
|
||||
int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
|
||||
int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct bonding *bond = netdev_priv(bond_dev);
|
||||
const struct net_device_ops *slave_ops = slave_dev->netdev_ops;
|
||||
@ -1346,12 +1348,14 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
|
||||
|
||||
/* already in-use? */
|
||||
if (netdev_is_rx_handler_busy(slave_dev)) {
|
||||
NL_SET_ERR_MSG(extack, "Device is in use and cannot be enslaved");
|
||||
netdev_err(bond_dev,
|
||||
"Error: Device is in use and cannot be enslaved\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (bond_dev == slave_dev) {
|
||||
NL_SET_ERR_MSG(extack, "Cannot enslave bond to itself.");
|
||||
netdev_err(bond_dev, "cannot enslave bond to itself.\n");
|
||||
return -EPERM;
|
||||
}
|
||||
@ -1362,6 +1366,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
|
||||
netdev_dbg(bond_dev, "%s is NETIF_F_VLAN_CHALLENGED\n",
|
||||
slave_dev->name);
|
||||
if (vlan_uses_dev(bond_dev)) {
|
||||
NL_SET_ERR_MSG(extack, "Can not enslave VLAN challenged device to VLAN enabled bond");
|
||||
netdev_err(bond_dev, "Error: cannot enslave VLAN challenged slave %s on VLAN enabled bond %s\n",
|
||||
slave_dev->name, bond_dev->name);
|
||||
return -EPERM;
|
||||
@ -1381,6 +1386,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
|
||||
* enslaving it; the old ifenslave will not.
|
||||
*/
|
||||
if (slave_dev->flags & IFF_UP) {
|
||||
NL_SET_ERR_MSG(extack, "Device can not be enslaved while up");
|
||||
netdev_err(bond_dev, "%s is up - this may be due to an out of date ifenslave\n",
|
||||
slave_dev->name);
|
||||
return -EPERM;
|
||||
@ -1421,6 +1427,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
|
||||
bond_dev);
|
||||
}
|
||||
} else if (bond_dev->type != slave_dev->type) {
|
||||
NL_SET_ERR_MSG(extack, "Device type is different from other slaves");
|
||||
netdev_err(bond_dev, "%s ether type (%d) is different from other slaves (%d), can not enslave it\n",
|
||||
slave_dev->name, slave_dev->type, bond_dev->type);
|
||||
return -EINVAL;
|
||||
@ -1428,6 +1435,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
|
||||
|
||||
if (slave_dev->type == ARPHRD_INFINIBAND &&
|
||||
BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) {
|
||||
NL_SET_ERR_MSG(extack, "Only active-backup mode is supported for infiniband slaves");
|
||||
netdev_warn(bond_dev, "Type (%d) supports only active-backup mode\n",
|
||||
slave_dev->type);
|
||||
res = -EOPNOTSUPP;
|
||||
@ -1443,6 +1451,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
|
||||
bond->params.fail_over_mac = BOND_FOM_ACTIVE;
|
||||
netdev_warn(bond_dev, "Setting fail_over_mac to active for active-backup mode\n");
|
||||
} else {
|
||||
NL_SET_ERR_MSG(extack, "Slave device does not support setting the MAC address, but fail_over_mac is not set to active");
|
||||
netdev_err(bond_dev, "The slave device specified does not support setting the MAC address, but fail_over_mac is not set to active\n");
|
||||
res = -EOPNOTSUPP;
|
||||
goto err_undo_flags;
|
||||
@ -1709,7 +1718,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
|
||||
goto err_detach;
|
||||
}
|
||||
|
||||
res = bond_master_upper_dev_link(bond, new_slave);
|
||||
res = bond_master_upper_dev_link(bond, new_slave, extack);
|
||||
if (res) {
|
||||
netdev_dbg(bond_dev, "Error %d calling bond_master_upper_dev_link\n", res);
|
||||
goto err_unregister;
|
||||
@ -3492,7 +3501,7 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
|
||||
switch (cmd) {
|
||||
case BOND_ENSLAVE_OLD:
|
||||
case SIOCBONDENSLAVE:
|
||||
res = bond_enslave(bond_dev, slave_dev);
|
||||
res = bond_enslave(bond_dev, slave_dev, NULL);
|
||||
break;
|
||||
case BOND_RELEASE_OLD:
|
||||
case SIOCBONDRELEASE:
|
||||
|
@ -1383,7 +1383,7 @@ static int bond_option_slaves_set(struct bonding *bond,
|
||||
switch (command[0]) {
|
||||
case '+':
|
||||
netdev_dbg(bond->dev, "Adding slave %s\n", dev->name);
|
||||
ret = bond_enslave(bond->dev, dev);
|
||||
ret = bond_enslave(bond->dev, dev, NULL);
|
||||
break;
|
||||
|
||||
case '-':
|
||||
|
@ -4019,14 +4019,21 @@ static int mlxsw_sp_lag_index_get(struct mlxsw_sp *mlxsw_sp,
|
||||
static bool
|
||||
mlxsw_sp_master_lag_check(struct mlxsw_sp *mlxsw_sp,
|
||||
struct net_device *lag_dev,
|
||||
struct netdev_lag_upper_info *lag_upper_info)
|
||||
struct netdev_lag_upper_info *lag_upper_info,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
u16 lag_id;
|
||||
|
||||
if (mlxsw_sp_lag_index_get(mlxsw_sp, lag_dev, &lag_id) != 0)
|
||||
if (mlxsw_sp_lag_index_get(mlxsw_sp, lag_dev, &lag_id) != 0) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"spectrum: Exceeded number of supported LAG devices");
|
||||
return false;
|
||||
if (lag_upper_info->tx_type != NETDEV_LAG_TX_TYPE_HASH)
|
||||
}
|
||||
if (lag_upper_info->tx_type != NETDEV_LAG_TX_TYPE_HASH) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"spectrum: LAG device using unsupported Tx type");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -4231,6 +4238,7 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev,
|
||||
{
|
||||
struct netdev_notifier_changeupper_info *info;
|
||||
struct mlxsw_sp_port *mlxsw_sp_port;
|
||||
struct netlink_ext_ack *extack;
|
||||
struct net_device *upper_dev;
|
||||
struct mlxsw_sp *mlxsw_sp;
|
||||
int err = 0;
|
||||
@ -4238,6 +4246,7 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev,
|
||||
mlxsw_sp_port = netdev_priv(dev);
|
||||
mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
|
||||
info = ptr;
|
||||
extack = netdev_notifier_info_to_extack(&info->info);
|
||||
|
||||
switch (event) {
|
||||
case NETDEV_PRECHANGEUPPER:
|
||||
@ -4245,25 +4254,43 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev,
|
||||
if (!is_vlan_dev(upper_dev) &&
|
||||
!netif_is_lag_master(upper_dev) &&
|
||||
!netif_is_bridge_master(upper_dev) &&
|
||||
!netif_is_ovs_master(upper_dev))
|
||||
!netif_is_ovs_master(upper_dev)) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"spectrum: Unknown upper device type");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!info->linking)
|
||||
break;
|
||||
if (netdev_has_any_upper_dev(upper_dev))
|
||||
if (netdev_has_any_upper_dev(upper_dev)) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"spectrum: Enslaving a port to a device that already has an upper device is not supported");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (netif_is_lag_master(upper_dev) &&
|
||||
!mlxsw_sp_master_lag_check(mlxsw_sp, upper_dev,
|
||||
info->upper_info))
|
||||
info->upper_info, extack))
|
||||
return -EINVAL;
|
||||
if (netif_is_lag_master(upper_dev) && vlan_uses_dev(dev))
|
||||
if (netif_is_lag_master(upper_dev) && vlan_uses_dev(dev)) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"spectrum: Master device is a LAG master and this device has a VLAN");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (netif_is_lag_port(dev) && is_vlan_dev(upper_dev) &&
|
||||
!netif_is_lag_master(vlan_dev_real_dev(upper_dev)))
|
||||
!netif_is_lag_master(vlan_dev_real_dev(upper_dev))) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"spectrum: Can not put a VLAN on a LAG port");
|
||||
return -EINVAL;
|
||||
if (netif_is_ovs_master(upper_dev) && vlan_uses_dev(dev))
|
||||
}
|
||||
if (netif_is_ovs_master(upper_dev) && vlan_uses_dev(dev)) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"spectrum: Master device is an OVS master and this device has a VLAN");
|
||||
return -EINVAL;
|
||||
if (netif_is_ovs_port(dev) && is_vlan_dev(upper_dev))
|
||||
}
|
||||
if (netif_is_ovs_port(dev) && is_vlan_dev(upper_dev)) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"spectrum: Can not put a VLAN on an OVS port");
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case NETDEV_CHANGEUPPER:
|
||||
upper_dev = info->upper_dev;
|
||||
|
@ -178,7 +178,7 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
|
||||
if (err)
|
||||
goto err1;
|
||||
|
||||
err = netdev_master_upper_dev_link(dev, real_dev, NULL, NULL);
|
||||
err = netdev_master_upper_dev_link(dev, real_dev, NULL, NULL, extack);
|
||||
if (err)
|
||||
goto err2;
|
||||
|
||||
|
@ -1748,7 +1748,7 @@ static int netvsc_vf_join(struct net_device *vf_netdev,
|
||||
goto rx_handler_failed;
|
||||
}
|
||||
|
||||
ret = netdev_upper_dev_link(vf_netdev, ndev);
|
||||
ret = netdev_upper_dev_link(vf_netdev, ndev, NULL);
|
||||
if (ret != 0) {
|
||||
netdev_err(vf_netdev,
|
||||
"can not set master device %s (err = %d)\n",
|
||||
|
@ -584,7 +584,7 @@ int ipvlan_link_new(struct net *src_net, struct net_device *dev,
|
||||
if (err < 0)
|
||||
goto remove_ida;
|
||||
|
||||
err = netdev_upper_dev_link(phy_dev, dev);
|
||||
err = netdev_upper_dev_link(phy_dev, dev, extack);
|
||||
if (err) {
|
||||
goto unregister_netdev;
|
||||
}
|
||||
|
@ -3244,7 +3244,7 @@ static int macsec_newlink(struct net *net, struct net_device *dev,
|
||||
&macsec_netdev_addr_lock_key,
|
||||
macsec_get_nest_level(dev));
|
||||
|
||||
err = netdev_upper_dev_link(real_dev, dev);
|
||||
err = netdev_upper_dev_link(real_dev, dev, extack);
|
||||
if (err < 0)
|
||||
goto unregister;
|
||||
|
||||
|
@ -1344,7 +1344,8 @@ static int macvlan_changelink_sources(struct macvlan_dev *vlan, u32 mode,
|
||||
}
|
||||
|
||||
int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
|
||||
struct nlattr *tb[], struct nlattr *data[])
|
||||
struct nlattr *tb[], struct nlattr *data[],
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct macvlan_dev *vlan = netdev_priv(dev);
|
||||
struct macvlan_port *port;
|
||||
@ -1433,7 +1434,7 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
|
||||
goto destroy_macvlan_port;
|
||||
|
||||
dev->priv_flags |= IFF_MACVLAN;
|
||||
err = netdev_upper_dev_link(lowerdev, dev);
|
||||
err = netdev_upper_dev_link(lowerdev, dev, extack);
|
||||
if (err)
|
||||
goto unregister_netdev;
|
||||
|
||||
@ -1456,7 +1457,7 @@ static int macvlan_newlink(struct net *src_net, struct net_device *dev,
|
||||
struct nlattr *tb[], struct nlattr *data[],
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
return macvlan_common_newlink(src_net, dev, tb, data);
|
||||
return macvlan_common_newlink(src_net, dev, tb, data, extack);
|
||||
}
|
||||
|
||||
void macvlan_dellink(struct net_device *dev, struct list_head *head)
|
||||
|
@ -105,7 +105,7 @@ static int macvtap_newlink(struct net *src_net, struct net_device *dev,
|
||||
/* Don't put anything that may fail after macvlan_common_newlink
|
||||
* because we can't undo what it does.
|
||||
*/
|
||||
err = macvlan_common_newlink(src_net, dev, tb, data);
|
||||
err = macvlan_common_newlink(src_net, dev, tb, data, extack);
|
||||
if (err) {
|
||||
netdev_rx_handler_unregister(dev);
|
||||
return err;
|
||||
|
@ -1112,7 +1112,7 @@ static int team_upper_dev_link(struct team *team, struct team_port *port)
|
||||
|
||||
lag_upper_info.tx_type = team->mode->lag_tx_type;
|
||||
err = netdev_master_upper_dev_link(port->dev, team->dev, NULL,
|
||||
&lag_upper_info);
|
||||
&lag_upper_info, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
port->dev->priv_flags |= IFF_TEAM_PORT;
|
||||
@ -1914,7 +1914,8 @@ static int team_netpoll_setup(struct net_device *dev,
|
||||
}
|
||||
#endif
|
||||
|
||||
static int team_add_slave(struct net_device *dev, struct net_device *port_dev)
|
||||
static int team_add_slave(struct net_device *dev, struct net_device *port_dev,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct team *team = netdev_priv(dev);
|
||||
int err;
|
||||
|
@ -221,7 +221,7 @@ static int qmimux_register_device(struct net_device *real_dev, u8 mux_id)
|
||||
/* Account for reference in struct qmimux_priv_priv */
|
||||
dev_hold(real_dev);
|
||||
|
||||
err = netdev_upper_dev_link(real_dev, new_dev);
|
||||
err = netdev_upper_dev_link(real_dev, new_dev, NULL);
|
||||
if (err)
|
||||
goto out_unregister_netdev;
|
||||
|
||||
|
@ -764,18 +764,22 @@ static void cycle_netdev(struct net_device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
static int do_vrf_add_slave(struct net_device *dev, struct net_device *port_dev)
|
||||
static int do_vrf_add_slave(struct net_device *dev, struct net_device *port_dev,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* do not allow loopback device to be enslaved to a VRF.
|
||||
* The vrf device acts as the loopback for the vrf.
|
||||
*/
|
||||
if (port_dev == dev_net(dev)->loopback_dev)
|
||||
if (port_dev == dev_net(dev)->loopback_dev) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"Can not enslave loopback device to a VRF");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
port_dev->priv_flags |= IFF_L3MDEV_SLAVE;
|
||||
ret = netdev_master_upper_dev_link(port_dev, dev, NULL, NULL);
|
||||
ret = netdev_master_upper_dev_link(port_dev, dev, NULL, NULL, extack);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
@ -788,12 +792,19 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vrf_add_slave(struct net_device *dev, struct net_device *port_dev)
|
||||
static int vrf_add_slave(struct net_device *dev, struct net_device *port_dev,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
if (netif_is_l3_master(port_dev) || netif_is_l3_slave(port_dev))
|
||||
if (netif_is_l3_master(port_dev)) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"Can not enslave an L3 master device to a VRF");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (netif_is_l3_slave(port_dev))
|
||||
return -EINVAL;
|
||||
|
||||
return do_vrf_add_slave(dev, port_dev);
|
||||
return do_vrf_add_slave(dev, port_dev, extack);
|
||||
}
|
||||
|
||||
/* inverse of do_vrf_add_slave */
|
||||
|
@ -72,7 +72,8 @@ static inline void macvlan_count_rx(const struct macvlan_dev *vlan,
|
||||
extern void macvlan_common_setup(struct net_device *dev);
|
||||
|
||||
extern int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
|
||||
struct nlattr *tb[], struct nlattr *data[]);
|
||||
struct nlattr *tb[], struct nlattr *data[],
|
||||
struct netlink_ext_ack *extack);
|
||||
|
||||
extern void macvlan_count_rx(const struct macvlan_dev *vlan,
|
||||
unsigned int len, bool success,
|
||||
|
@ -1246,7 +1246,8 @@ struct net_device_ops {
|
||||
u32 flow_id);
|
||||
#endif
|
||||
int (*ndo_add_slave)(struct net_device *dev,
|
||||
struct net_device *slave_dev);
|
||||
struct net_device *slave_dev,
|
||||
struct netlink_ext_ack *extack);
|
||||
int (*ndo_del_slave)(struct net_device *dev,
|
||||
struct net_device *slave_dev);
|
||||
netdev_features_t (*ndo_fix_features)(struct net_device *dev,
|
||||
@ -2309,7 +2310,8 @@ int register_netdevice_notifier(struct notifier_block *nb);
|
||||
int unregister_netdevice_notifier(struct notifier_block *nb);
|
||||
|
||||
struct netdev_notifier_info {
|
||||
struct net_device *dev;
|
||||
struct net_device *dev;
|
||||
struct netlink_ext_ack *extack;
|
||||
};
|
||||
|
||||
struct netdev_notifier_change_info {
|
||||
@ -2334,6 +2336,7 @@ static inline void netdev_notifier_info_init(struct netdev_notifier_info *info,
|
||||
struct net_device *dev)
|
||||
{
|
||||
info->dev = dev;
|
||||
info->extack = NULL;
|
||||
}
|
||||
|
||||
static inline struct net_device *
|
||||
@ -2342,6 +2345,12 @@ netdev_notifier_info_to_dev(const struct netdev_notifier_info *info)
|
||||
return info->dev;
|
||||
}
|
||||
|
||||
static inline struct netlink_ext_ack *
|
||||
netdev_notifier_info_to_extack(const struct netdev_notifier_info *info)
|
||||
{
|
||||
return info->extack;
|
||||
}
|
||||
|
||||
int call_netdevice_notifiers(unsigned long val, struct net_device *dev);
|
||||
|
||||
|
||||
@ -3910,10 +3919,12 @@ void *netdev_adjacent_get_private(struct list_head *adj_list);
|
||||
void *netdev_lower_get_first_private_rcu(struct net_device *dev);
|
||||
struct net_device *netdev_master_upper_dev_get(struct net_device *dev);
|
||||
struct net_device *netdev_master_upper_dev_get_rcu(struct net_device *dev);
|
||||
int netdev_upper_dev_link(struct net_device *dev, struct net_device *upper_dev);
|
||||
int netdev_upper_dev_link(struct net_device *dev, struct net_device *upper_dev,
|
||||
struct netlink_ext_ack *extack);
|
||||
int netdev_master_upper_dev_link(struct net_device *dev,
|
||||
struct net_device *upper_dev,
|
||||
void *upper_priv, void *upper_info);
|
||||
void *upper_priv, void *upper_info,
|
||||
struct netlink_ext_ack *extack);
|
||||
void netdev_upper_dev_unlink(struct net_device *dev,
|
||||
struct net_device *upper_dev);
|
||||
void netdev_adjacent_rename_links(struct net_device *dev, char *oldname);
|
||||
|
@ -596,7 +596,8 @@ void bond_destroy_sysfs(struct bond_net *net);
|
||||
void bond_prepare_sysfs_group(struct bonding *bond);
|
||||
int bond_sysfs_slave_add(struct slave *slave);
|
||||
void bond_sysfs_slave_del(struct slave *slave);
|
||||
int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev);
|
||||
int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
|
||||
struct netlink_ext_ack *extack);
|
||||
int bond_release(struct net_device *bond_dev, struct net_device *slave_dev);
|
||||
u32 bond_xmit_hash(struct bonding *bond, struct sk_buff *skb);
|
||||
int bond_set_carrier(struct bonding *bond);
|
||||
|
@ -138,7 +138,7 @@ int vlan_check_real_dev(struct net_device *real_dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int register_vlan_dev(struct net_device *dev)
|
||||
int register_vlan_dev(struct net_device *dev, struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
|
||||
struct net_device *real_dev = vlan->real_dev;
|
||||
@ -174,7 +174,7 @@ int register_vlan_dev(struct net_device *dev)
|
||||
if (err < 0)
|
||||
goto out_uninit_mvrp;
|
||||
|
||||
err = netdev_upper_dev_link(real_dev, dev);
|
||||
err = netdev_upper_dev_link(real_dev, dev, extack);
|
||||
if (err)
|
||||
goto out_unregister_netdev;
|
||||
|
||||
@ -270,7 +270,7 @@ static int register_vlan_device(struct net_device *real_dev, u16 vlan_id)
|
||||
vlan->flags = VLAN_FLAG_REORDER_HDR;
|
||||
|
||||
new_dev->rtnl_link_ops = &vlan_link_ops;
|
||||
err = register_vlan_dev(new_dev);
|
||||
err = register_vlan_dev(new_dev, NULL);
|
||||
if (err < 0)
|
||||
goto out_free_newdev;
|
||||
|
||||
|
@ -107,7 +107,7 @@ void vlan_dev_get_realdev_name(const struct net_device *dev, char *result);
|
||||
int vlan_check_real_dev(struct net_device *real_dev,
|
||||
__be16 protocol, u16 vlan_id);
|
||||
void vlan_setup(struct net_device *dev);
|
||||
int register_vlan_dev(struct net_device *dev);
|
||||
int register_vlan_dev(struct net_device *dev, struct netlink_ext_ack *extack);
|
||||
void unregister_vlan_dev(struct net_device *dev, struct list_head *head);
|
||||
bool vlan_dev_inherit_address(struct net_device *dev,
|
||||
struct net_device *real_dev);
|
||||
|
@ -160,7 +160,7 @@ static int vlan_newlink(struct net *src_net, struct net_device *dev,
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return register_vlan_dev(dev);
|
||||
return register_vlan_dev(dev, extack);
|
||||
}
|
||||
|
||||
static inline size_t vlan_qos_map_size(unsigned int n)
|
||||
|
@ -738,7 +738,7 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
|
||||
bat_priv = netdev_priv(hard_iface->soft_iface);
|
||||
|
||||
ret = netdev_master_upper_dev_link(hard_iface->net_dev,
|
||||
soft_iface, NULL, NULL);
|
||||
soft_iface, NULL, NULL, NULL);
|
||||
if (ret)
|
||||
goto err_dev;
|
||||
|
||||
|
@ -867,7 +867,8 @@ free_bat_counters:
|
||||
* Return: 0 if successful or error otherwise.
|
||||
*/
|
||||
static int batadv_softif_slave_add(struct net_device *dev,
|
||||
struct net_device *slave_dev)
|
||||
struct net_device *slave_dev,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct batadv_hard_iface *hard_iface;
|
||||
struct net *net = dev_net(dev);
|
||||
|
@ -320,12 +320,13 @@ void br_netpoll_disable(struct net_bridge_port *p)
|
||||
|
||||
#endif
|
||||
|
||||
static int br_add_slave(struct net_device *dev, struct net_device *slave_dev)
|
||||
static int br_add_slave(struct net_device *dev, struct net_device *slave_dev,
|
||||
struct netlink_ext_ack *extack)
|
||||
|
||||
{
|
||||
struct net_bridge *br = netdev_priv(dev);
|
||||
|
||||
return br_add_if(br, slave_dev);
|
||||
return br_add_if(br, slave_dev, extack);
|
||||
}
|
||||
|
||||
static int br_del_slave(struct net_device *dev, struct net_device *slave_dev)
|
||||
|
@ -480,7 +480,8 @@ netdev_features_t br_features_recompute(struct net_bridge *br,
|
||||
}
|
||||
|
||||
/* called with RTNL */
|
||||
int br_add_if(struct net_bridge *br, struct net_device *dev)
|
||||
int br_add_if(struct net_bridge *br, struct net_device *dev,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct net_bridge_port *p;
|
||||
int err = 0;
|
||||
@ -500,16 +501,22 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
|
||||
return -EINVAL;
|
||||
|
||||
/* No bridging of bridges */
|
||||
if (dev->netdev_ops->ndo_start_xmit == br_dev_xmit)
|
||||
if (dev->netdev_ops->ndo_start_xmit == br_dev_xmit) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"Can not enslave a bridge to a bridge");
|
||||
return -ELOOP;
|
||||
}
|
||||
|
||||
/* Device is already being bridged */
|
||||
if (br_port_exists(dev))
|
||||
return -EBUSY;
|
||||
|
||||
/* No bridging devices that dislike that (e.g. wireless) */
|
||||
if (dev->priv_flags & IFF_DONT_BRIDGE)
|
||||
if (dev->priv_flags & IFF_DONT_BRIDGE) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"Device does not allow enslaving to a bridge");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
p = new_nbp(br, dev);
|
||||
if (IS_ERR(p))
|
||||
@ -540,7 +547,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
|
||||
|
||||
dev->priv_flags |= IFF_BRIDGE_PORT;
|
||||
|
||||
err = netdev_master_upper_dev_link(dev, br->dev, NULL, NULL);
|
||||
err = netdev_master_upper_dev_link(dev, br->dev, NULL, NULL, extack);
|
||||
if (err)
|
||||
goto err5;
|
||||
|
||||
|
@ -98,7 +98,7 @@ static int add_del_if(struct net_bridge *br, int ifindex, int isadd)
|
||||
return -EINVAL;
|
||||
|
||||
if (isadd)
|
||||
ret = br_add_if(br, dev);
|
||||
ret = br_add_if(br, dev, NULL);
|
||||
else
|
||||
ret = br_del_if(br, dev);
|
||||
|
||||
|
@ -566,7 +566,8 @@ void br_flood(struct net_bridge *br, struct sk_buff *skb,
|
||||
void br_port_carrier_check(struct net_bridge_port *p);
|
||||
int br_add_bridge(struct net *net, const char *name);
|
||||
int br_del_bridge(struct net *net, const char *name);
|
||||
int br_add_if(struct net_bridge *br, struct net_device *dev);
|
||||
int br_add_if(struct net_bridge *br, struct net_device *dev,
|
||||
struct netlink_ext_ack *extack);
|
||||
int br_del_if(struct net_bridge *br, struct net_device *dev);
|
||||
int br_min_mtu(const struct net_bridge *br);
|
||||
netdev_features_t br_features_recompute(struct net_bridge *br,
|
||||
|
@ -163,7 +163,6 @@ static struct list_head offload_base __read_mostly;
|
||||
|
||||
static int netif_rx_internal(struct sk_buff *skb);
|
||||
static int call_netdevice_notifiers_info(unsigned long val,
|
||||
struct net_device *dev,
|
||||
struct netdev_notifier_info *info);
|
||||
static struct napi_struct *napi_by_id(unsigned int napi_id);
|
||||
|
||||
@ -1339,10 +1338,11 @@ EXPORT_SYMBOL(netdev_features_change);
|
||||
void netdev_state_change(struct net_device *dev)
|
||||
{
|
||||
if (dev->flags & IFF_UP) {
|
||||
struct netdev_notifier_change_info change_info;
|
||||
struct netdev_notifier_change_info change_info = {
|
||||
.info.dev = dev,
|
||||
};
|
||||
|
||||
change_info.flags_changed = 0;
|
||||
call_netdevice_notifiers_info(NETDEV_CHANGE, dev,
|
||||
call_netdevice_notifiers_info(NETDEV_CHANGE,
|
||||
&change_info.info);
|
||||
rtmsg_ifinfo(RTM_NEWLINK, dev, 0, GFP_KERNEL);
|
||||
}
|
||||
@ -1563,9 +1563,10 @@ EXPORT_SYMBOL(dev_disable_lro);
|
||||
static int call_netdevice_notifier(struct notifier_block *nb, unsigned long val,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct netdev_notifier_info info;
|
||||
struct netdev_notifier_info info = {
|
||||
.dev = dev,
|
||||
};
|
||||
|
||||
netdev_notifier_info_init(&info, dev);
|
||||
return nb->notifier_call(nb, val, &info);
|
||||
}
|
||||
|
||||
@ -1690,11 +1691,9 @@ EXPORT_SYMBOL(unregister_netdevice_notifier);
|
||||
*/
|
||||
|
||||
static int call_netdevice_notifiers_info(unsigned long val,
|
||||
struct net_device *dev,
|
||||
struct netdev_notifier_info *info)
|
||||
{
|
||||
ASSERT_RTNL();
|
||||
netdev_notifier_info_init(info, dev);
|
||||
return raw_notifier_call_chain(&netdev_chain, val, info);
|
||||
}
|
||||
|
||||
@ -1709,9 +1708,11 @@ static int call_netdevice_notifiers_info(unsigned long val,
|
||||
|
||||
int call_netdevice_notifiers(unsigned long val, struct net_device *dev)
|
||||
{
|
||||
struct netdev_notifier_info info;
|
||||
struct netdev_notifier_info info = {
|
||||
.dev = dev,
|
||||
};
|
||||
|
||||
return call_netdevice_notifiers_info(val, dev, &info);
|
||||
return call_netdevice_notifiers_info(val, &info);
|
||||
}
|
||||
EXPORT_SYMBOL(call_netdevice_notifiers);
|
||||
|
||||
@ -6276,9 +6277,19 @@ static void __netdev_adjacent_dev_unlink_neighbour(struct net_device *dev,
|
||||
|
||||
static int __netdev_upper_dev_link(struct net_device *dev,
|
||||
struct net_device *upper_dev, bool master,
|
||||
void *upper_priv, void *upper_info)
|
||||
void *upper_priv, void *upper_info,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct netdev_notifier_changeupper_info changeupper_info;
|
||||
struct netdev_notifier_changeupper_info changeupper_info = {
|
||||
.info = {
|
||||
.dev = dev,
|
||||
.extack = extack,
|
||||
},
|
||||
.upper_dev = upper_dev,
|
||||
.master = master,
|
||||
.linking = true,
|
||||
.upper_info = upper_info,
|
||||
};
|
||||
int ret = 0;
|
||||
|
||||
ASSERT_RTNL();
|
||||
@ -6296,12 +6307,7 @@ static int __netdev_upper_dev_link(struct net_device *dev,
|
||||
if (master && netdev_master_upper_dev_get(dev))
|
||||
return -EBUSY;
|
||||
|
||||
changeupper_info.upper_dev = upper_dev;
|
||||
changeupper_info.master = master;
|
||||
changeupper_info.linking = true;
|
||||
changeupper_info.upper_info = upper_info;
|
||||
|
||||
ret = call_netdevice_notifiers_info(NETDEV_PRECHANGEUPPER, dev,
|
||||
ret = call_netdevice_notifiers_info(NETDEV_PRECHANGEUPPER,
|
||||
&changeupper_info.info);
|
||||
ret = notifier_to_errno(ret);
|
||||
if (ret)
|
||||
@ -6312,7 +6318,7 @@ static int __netdev_upper_dev_link(struct net_device *dev,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, dev,
|
||||
ret = call_netdevice_notifiers_info(NETDEV_CHANGEUPPER,
|
||||
&changeupper_info.info);
|
||||
ret = notifier_to_errno(ret);
|
||||
if (ret)
|
||||
@ -6337,9 +6343,11 @@ rollback:
|
||||
* returns zero.
|
||||
*/
|
||||
int netdev_upper_dev_link(struct net_device *dev,
|
||||
struct net_device *upper_dev)
|
||||
struct net_device *upper_dev,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
return __netdev_upper_dev_link(dev, upper_dev, false, NULL, NULL);
|
||||
return __netdev_upper_dev_link(dev, upper_dev, false,
|
||||
NULL, NULL, extack);
|
||||
}
|
||||
EXPORT_SYMBOL(netdev_upper_dev_link);
|
||||
|
||||
@ -6358,10 +6366,11 @@ EXPORT_SYMBOL(netdev_upper_dev_link);
|
||||
*/
|
||||
int netdev_master_upper_dev_link(struct net_device *dev,
|
||||
struct net_device *upper_dev,
|
||||
void *upper_priv, void *upper_info)
|
||||
void *upper_priv, void *upper_info,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
return __netdev_upper_dev_link(dev, upper_dev, true,
|
||||
upper_priv, upper_info);
|
||||
upper_priv, upper_info, extack);
|
||||
}
|
||||
EXPORT_SYMBOL(netdev_master_upper_dev_link);
|
||||
|
||||
@ -6376,20 +6385,24 @@ EXPORT_SYMBOL(netdev_master_upper_dev_link);
|
||||
void netdev_upper_dev_unlink(struct net_device *dev,
|
||||
struct net_device *upper_dev)
|
||||
{
|
||||
struct netdev_notifier_changeupper_info changeupper_info;
|
||||
struct netdev_notifier_changeupper_info changeupper_info = {
|
||||
.info = {
|
||||
.dev = dev,
|
||||
},
|
||||
.upper_dev = upper_dev,
|
||||
.linking = false,
|
||||
};
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
changeupper_info.upper_dev = upper_dev;
|
||||
changeupper_info.master = netdev_master_upper_dev_get(dev) == upper_dev;
|
||||
changeupper_info.linking = false;
|
||||
|
||||
call_netdevice_notifiers_info(NETDEV_PRECHANGEUPPER, dev,
|
||||
call_netdevice_notifiers_info(NETDEV_PRECHANGEUPPER,
|
||||
&changeupper_info.info);
|
||||
|
||||
__netdev_adjacent_dev_unlink_neighbour(dev, upper_dev);
|
||||
|
||||
call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, dev,
|
||||
call_netdevice_notifiers_info(NETDEV_CHANGEUPPER,
|
||||
&changeupper_info.info);
|
||||
}
|
||||
EXPORT_SYMBOL(netdev_upper_dev_unlink);
|
||||
@ -6405,11 +6418,13 @@ EXPORT_SYMBOL(netdev_upper_dev_unlink);
|
||||
void netdev_bonding_info_change(struct net_device *dev,
|
||||
struct netdev_bonding_info *bonding_info)
|
||||
{
|
||||
struct netdev_notifier_bonding_info info;
|
||||
struct netdev_notifier_bonding_info info = {
|
||||
.info.dev = dev,
|
||||
};
|
||||
|
||||
memcpy(&info.bonding_info, bonding_info,
|
||||
sizeof(struct netdev_bonding_info));
|
||||
call_netdevice_notifiers_info(NETDEV_BONDING_INFO, dev,
|
||||
call_netdevice_notifiers_info(NETDEV_BONDING_INFO,
|
||||
&info.info);
|
||||
}
|
||||
EXPORT_SYMBOL(netdev_bonding_info_change);
|
||||
@ -6535,11 +6550,13 @@ EXPORT_SYMBOL(dev_get_nest_level);
|
||||
void netdev_lower_state_changed(struct net_device *lower_dev,
|
||||
void *lower_state_info)
|
||||
{
|
||||
struct netdev_notifier_changelowerstate_info changelowerstate_info;
|
||||
struct netdev_notifier_changelowerstate_info changelowerstate_info = {
|
||||
.info.dev = lower_dev,
|
||||
};
|
||||
|
||||
ASSERT_RTNL();
|
||||
changelowerstate_info.lower_state_info = lower_state_info;
|
||||
call_netdevice_notifiers_info(NETDEV_CHANGELOWERSTATE, lower_dev,
|
||||
call_netdevice_notifiers_info(NETDEV_CHANGELOWERSTATE,
|
||||
&changelowerstate_info.info);
|
||||
}
|
||||
EXPORT_SYMBOL(netdev_lower_state_changed);
|
||||
@ -6830,11 +6847,14 @@ void __dev_notify_flags(struct net_device *dev, unsigned int old_flags,
|
||||
|
||||
if (dev->flags & IFF_UP &&
|
||||
(changes & ~(IFF_UP | IFF_PROMISC | IFF_ALLMULTI | IFF_VOLATILE))) {
|
||||
struct netdev_notifier_change_info change_info;
|
||||
struct netdev_notifier_change_info change_info = {
|
||||
.info = {
|
||||
.dev = dev,
|
||||
},
|
||||
.flags_changed = changes,
|
||||
};
|
||||
|
||||
change_info.flags_changed = changes;
|
||||
call_netdevice_notifiers_info(NETDEV_CHANGE, dev,
|
||||
&change_info.info);
|
||||
call_netdevice_notifiers_info(NETDEV_CHANGE, &change_info.info);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1957,7 +1957,8 @@ static int do_setvfinfo(struct net_device *dev, struct nlattr **tb)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int do_set_master(struct net_device *dev, int ifindex)
|
||||
static int do_set_master(struct net_device *dev, int ifindex,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct net_device *upper_dev = netdev_master_upper_dev_get(dev);
|
||||
const struct net_device_ops *ops;
|
||||
@ -1982,7 +1983,7 @@ static int do_set_master(struct net_device *dev, int ifindex)
|
||||
return -EINVAL;
|
||||
ops = upper_dev->netdev_ops;
|
||||
if (ops->ndo_add_slave) {
|
||||
err = ops->ndo_add_slave(upper_dev, dev);
|
||||
err = ops->ndo_add_slave(upper_dev, dev, extack);
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
@ -2115,7 +2116,7 @@ static int do_setlink(const struct sk_buff *skb,
|
||||
}
|
||||
|
||||
if (tb[IFLA_MASTER]) {
|
||||
err = do_set_master(dev, nla_get_u32(tb[IFLA_MASTER]));
|
||||
err = do_set_master(dev, nla_get_u32(tb[IFLA_MASTER]), extack);
|
||||
if (err)
|
||||
goto errout;
|
||||
status |= DO_SETLINK_MODIFIED;
|
||||
@ -2753,7 +2754,8 @@ replay:
|
||||
goto out_unregister;
|
||||
}
|
||||
if (tb[IFLA_MASTER]) {
|
||||
err = do_set_master(dev, nla_get_u32(tb[IFLA_MASTER]));
|
||||
err = do_set_master(dev, nla_get_u32(tb[IFLA_MASTER]),
|
||||
extack);
|
||||
if (err)
|
||||
goto out_unregister;
|
||||
}
|
||||
|
@ -108,7 +108,8 @@ struct vport *ovs_netdev_link(struct vport *vport, const char *name)
|
||||
|
||||
rtnl_lock();
|
||||
err = netdev_master_upper_dev_link(vport->dev,
|
||||
get_dpdev(vport->dp), NULL, NULL);
|
||||
get_dpdev(vport->dp),
|
||||
NULL, NULL, NULL);
|
||||
if (err)
|
||||
goto error_unlock;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user