macvlan: add VLAN filters to lowerdev
authorJohn Fastabend <john.r.fastabend@intel.com>
Mon, 6 Jun 2011 04:27:16 +0000 (04:27 +0000)
committerDavid S. Miller <davem@davemloft.net>
Mon, 6 Jun 2011 23:43:43 +0000 (16:43 -0700)
Stacking VLANs on top of the macvlan device does not
work if the lowerdev device is using vlan filters set
by NETIF_F_HW_VLAN_FILTER. Add ndo ops to pass vlan
calls to lowerdev.

Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/macvlan.c

index d6aeaa5f25eaa86df9780d03783b548631e92262..cc67cbe670cbd5133133b467ce8f9e6fcea44908 100644 (file)
@@ -414,7 +414,8 @@ 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 | \
         NETIF_F_GSO | NETIF_F_TSO | NETIF_F_UFO | NETIF_F_GSO_ROBUST | \
-        NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GRO | NETIF_F_RXCSUM)
+        NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GRO | NETIF_F_RXCSUM | \
+        NETIF_F_HW_VLAN_FILTER)
 
 #define MACVLAN_STATE_MASK \
        ((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT))
@@ -509,6 +510,39 @@ static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev,
        return stats;
 }
 
+static void macvlan_vlan_rx_register(struct net_device *dev,
+                                    struct vlan_group *grp)
+{
+       struct macvlan_dev *vlan = netdev_priv(dev);
+       struct net_device *lowerdev = vlan->lowerdev;
+       const struct net_device_ops *ops = lowerdev->netdev_ops;
+
+       if (ops->ndo_vlan_rx_register)
+               ops->ndo_vlan_rx_register(lowerdev, grp);
+}
+
+static void macvlan_vlan_rx_add_vid(struct net_device *dev,
+                                   unsigned short vid)
+{
+       struct macvlan_dev *vlan = netdev_priv(dev);
+       struct net_device *lowerdev = vlan->lowerdev;
+       const struct net_device_ops *ops = lowerdev->netdev_ops;
+
+       if (ops->ndo_vlan_rx_add_vid)
+               ops->ndo_vlan_rx_add_vid(lowerdev, vid);
+}
+
+static void macvlan_vlan_rx_kill_vid(struct net_device *dev,
+                                    unsigned short vid)
+{
+       struct macvlan_dev *vlan = netdev_priv(dev);
+       struct net_device *lowerdev = vlan->lowerdev;
+       const struct net_device_ops *ops = lowerdev->netdev_ops;
+
+       if (ops->ndo_vlan_rx_kill_vid)
+               ops->ndo_vlan_rx_kill_vid(lowerdev, vid);
+}
+
 static void macvlan_ethtool_get_drvinfo(struct net_device *dev,
                                        struct ethtool_drvinfo *drvinfo)
 {
@@ -541,6 +575,9 @@ static const struct net_device_ops macvlan_netdev_ops = {
        .ndo_set_multicast_list = macvlan_set_multicast_list,
        .ndo_get_stats64        = macvlan_dev_get_stats64,
        .ndo_validate_addr      = eth_validate_addr,
+       .ndo_vlan_rx_register   = macvlan_vlan_rx_register,
+       .ndo_vlan_rx_add_vid    = macvlan_vlan_rx_add_vid,
+       .ndo_vlan_rx_kill_vid   = macvlan_vlan_rx_kill_vid,
 };
 
 void macvlan_common_setup(struct net_device *dev)