aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2013-12-26 06:17:00 -0500
committerDavid S. Miller <davem@davemloft.net>2013-12-26 13:41:00 -0500
commit797f87f83b60685ff8a13fa0572d2f10393c50d3 (patch)
tree3ccec3d1c8085f47cb064e0e47490e459c4248bc /drivers/net
parent61e7f09d0f437c9614029445754099383ec2eec4 (diff)
macvlan: fix netdev feature propagation from lower device
There are inconsistencies wrt. feature propagation/inheritance between macvlan and the underlying interface. When a feature is turned off on the real device before a macvlan is created on top, these will remain enabled on the macvlan device, whereas turning off the feature on the lower device after macvlan creation the kernel will propagate the changes to the macvlan. The second issue is that, when propagating changes from underlying device to the macvlan interface, macvlan can erronously lose its NETIF_F_LLTX flag, as features are anded with the underlying device. However, LLTX should be kept since it has no dependencies on physical hardware (LLTX is set on macvlan creation regardless of the lower device properties, see 8ffab51b3dfc54876f145f15b351c41f3f703195 (macvlan: lockless tx path). The LLTX flag is now forced regardless of user settings in absence of layer2 hw acceleration (a6cc0cfa72e0b6d9f2c8fd858aa, net: Add layer 2 hardware acceleration operations for macvlan devices). Use netdev_increment_features to rebuild the feature set on capability changes on either the lower device or on the macvlan interface. As pointed out by Ben Hutchings, use netdev_update_features on NETDEV_FEAT_CHANGE event (it calls macvlan_fix_features/netdev_features_change if needed). Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/macvlan.c16
1 files changed, 13 insertions, 3 deletions
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index acf93798dc67..60406b01f9eb 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -690,8 +690,19 @@ static netdev_features_t macvlan_fix_features(struct net_device *dev,
690 netdev_features_t features) 690 netdev_features_t features)
691{ 691{
692 struct macvlan_dev *vlan = netdev_priv(dev); 692 struct macvlan_dev *vlan = netdev_priv(dev);
693 netdev_features_t mask;
693 694
694 return features & (vlan->set_features | ~MACVLAN_FEATURES); 695 features |= NETIF_F_ALL_FOR_ALL;
696 features &= (vlan->set_features | ~MACVLAN_FEATURES);
697 mask = features;
698
699 features = netdev_increment_features(vlan->lowerdev->features,
700 features,
701 mask);
702 if (!vlan->fwd_priv)
703 features |= NETIF_F_LLTX;
704
705 return features;
695} 706}
696 707
697static const struct ethtool_ops macvlan_ethtool_ops = { 708static const struct ethtool_ops macvlan_ethtool_ops = {
@@ -1019,9 +1030,8 @@ static int macvlan_device_event(struct notifier_block *unused,
1019 break; 1030 break;
1020 case NETDEV_FEAT_CHANGE: 1031 case NETDEV_FEAT_CHANGE:
1021 list_for_each_entry(vlan, &port->vlans, list) { 1032 list_for_each_entry(vlan, &port->vlans, list) {
1022 vlan->dev->features = dev->features & MACVLAN_FEATURES;
1023 vlan->dev->gso_max_size = dev->gso_max_size; 1033 vlan->dev->gso_max_size = dev->gso_max_size;
1024 netdev_features_change(vlan->dev); 1034 netdev_update_features(vlan->dev);
1025 } 1035 }
1026 break; 1036 break;
1027 case NETDEV_UNREGISTER: 1037 case NETDEV_UNREGISTER: