err = dev_unicast_add(lowerdev, dev->dev_addr, ETH_ALEN);
if (err < 0)
- return err;
- if (dev->flags & IFF_ALLMULTI)
- dev_set_allmulti(lowerdev, 1);
+ goto out;
+ if (dev->flags & IFF_ALLMULTI) {
+ err = dev_set_allmulti(lowerdev, 1);
+ if (err < 0)
+ goto del_unicast;
+ }
hlist_add_head_rcu(&vlan->hlist, &port->vlan_hash[dev->dev_addr[5]]);
return 0;
+
+del_unicast:
+ dev_unicast_delete(lowerdev, dev->dev_addr, ETH_ALEN);
+out:
+ return err;
}
static int macvlan_stop(struct net_device *dev)
* separate class since they always nest.
*/
static struct lock_class_key macvlan_netdev_xmit_lock_key;
+static struct lock_class_key macvlan_netdev_addr_lock_key;
#define MACVLAN_FEATURES \
(NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \
#define MACVLAN_STATE_MASK \
((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT))
+static void macvlan_set_lockdep_class_one(struct net_device *dev,
+ struct netdev_queue *txq,
+ void *_unused)
+{
+ lockdep_set_class(&txq->_xmit_lock,
+ &macvlan_netdev_xmit_lock_key);
+}
+
+static void macvlan_set_lockdep_class(struct net_device *dev)
+{
+ lockdep_set_class(&dev->addr_list_lock,
+ &macvlan_netdev_addr_lock_key);
+ netdev_for_each_tx_queue(dev, macvlan_set_lockdep_class_one, NULL);
+}
+
static int macvlan_init(struct net_device *dev)
{
struct macvlan_dev *vlan = netdev_priv(dev);
dev->features = lowerdev->features & MACVLAN_FEATURES;
dev->iflink = lowerdev->ifindex;
- lockdep_set_class(&dev->_xmit_lock, &macvlan_netdev_xmit_lock_key);
+ macvlan_set_lockdep_class(dev);
+
return 0;
}
return lowerdev->ethtool_ops->get_rx_csum(lowerdev);
}
+static int macvlan_ethtool_get_settings(struct net_device *dev,
+ struct ethtool_cmd *cmd)
+{
+ const struct macvlan_dev *vlan = netdev_priv(dev);
+ struct net_device *lowerdev = vlan->lowerdev;
+
+ if (!lowerdev->ethtool_ops->get_settings)
+ return -EOPNOTSUPP;
+
+ return lowerdev->ethtool_ops->get_settings(lowerdev, cmd);
+}
+
+static u32 macvlan_ethtool_get_flags(struct net_device *dev)
+{
+ const struct macvlan_dev *vlan = netdev_priv(dev);
+ struct net_device *lowerdev = vlan->lowerdev;
+
+ if (!lowerdev->ethtool_ops->get_flags)
+ return 0;
+ return lowerdev->ethtool_ops->get_flags(lowerdev);
+}
+
static const struct ethtool_ops macvlan_ethtool_ops = {
.get_link = ethtool_op_get_link,
+ .get_settings = macvlan_ethtool_get_settings,
.get_rx_csum = macvlan_ethtool_get_rx_csum,
.get_drvinfo = macvlan_ethtool_get_drvinfo,
+ .get_flags = macvlan_ethtool_get_flags,
};
static void macvlan_setup(struct net_device *dev)