[VLAN]: Propagate selected feature bits to VLAN devices
Patrick McHardy [Tue, 20 May 2008 21:54:50 +0000 (14:54 -0700)]
Propagate feature bits from the NETDEV_FEAT_CHANGE notifier. For now
only TSO is propagated for devices that announce their ability to
support TSO in combination with VLAN accel by setting the NETIF_F_VLAN_TSO
flag.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>

include/linux/netdevice.h
net/8021q/vlan.c
net/8021q/vlan.h
net/8021q/vlan_dev.c

index b11e6e1..2b02664 100644 (file)
@@ -514,10 +514,12 @@ struct net_device
 #define NETIF_F_NETNS_LOCAL    8192    /* Does not change network namespaces */
 #define NETIF_F_MULTI_QUEUE    16384   /* Has multiple TX/RX queues */
 #define NETIF_F_LRO            32768   /* large receive offload */
+#define NETIF_F_VLAN_TSO       65536   /* Supports TSO for VLANs */
+#define NETIF_F_VLAN_CSUM      131072  /* Supports TX checksumming for VLANs */
 
        /* Segmentation offload features */
-#define NETIF_F_GSO_SHIFT      16
-#define NETIF_F_GSO_MASK       0xffff0000
+#define NETIF_F_GSO_SHIFT      20
+#define NETIF_F_GSO_MASK       0xfff00000
 #define NETIF_F_TSO            (SKB_GSO_TCPV4 << NETIF_F_GSO_SHIFT)
 #define NETIF_F_UFO            (SKB_GSO_UDP << NETIF_F_GSO_SHIFT)
 #define NETIF_F_GSO_ROBUST     (SKB_GSO_DODGY << NETIF_F_GSO_SHIFT)
index b934159..5196130 100644 (file)
@@ -382,6 +382,24 @@ static void vlan_sync_address(struct net_device *dev,
        memcpy(vlan->real_dev_addr, dev->dev_addr, ETH_ALEN);
 }
 
+static void vlan_transfer_features(struct net_device *dev,
+                                  struct net_device *vlandev)
+{
+       unsigned long old_features = vlandev->features;
+
+       if (dev->features & NETIF_F_VLAN_TSO) {
+               vlandev->features &= ~VLAN_TSO_FEATURES;
+               vlandev->features |= dev->features & VLAN_TSO_FEATURES;
+       }
+       if (dev->features & NETIF_F_VLAN_CSUM) {
+               vlandev->features &= ~NETIF_F_ALL_CSUM;
+               vlandev->features |= dev->features & NETIF_F_ALL_CSUM;
+       }
+
+       if (old_features != vlandev->features)
+               netdev_features_change(vlandev);
+}
+
 static void __vlan_device_event(struct net_device *dev, unsigned long event)
 {
        switch (event) {
@@ -448,6 +466,18 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
                }
                break;
 
+       case NETDEV_FEAT_CHANGE:
+               /* Propagate device features to underlying device */
+               for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
+                       vlandev = vlan_group_get_device(grp, i);
+                       if (!vlandev)
+                               continue;
+
+                       vlan_transfer_features(dev, vlandev);
+               }
+
+               break;
+
        case NETDEV_DOWN:
                /* Put all VLANs for this dev in the down state too.  */
                for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
index 5229a72..7962569 100644 (file)
@@ -7,6 +7,8 @@
 #define VLAN_GRP_HASH_SIZE     (1 << VLAN_GRP_HASH_SHIFT)
 #define VLAN_GRP_HASH_MASK     (VLAN_GRP_HASH_SIZE - 1)
 
+#define VLAN_TSO_FEATURES      (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_SG)
+
 /*  Find a VLAN device by the MAC address of its Ethernet device, and
  *  it's VLAN ID.  The default configuration is to have VLAN's scope
  *  to be box-wide, so the MAC will be ignored.  The mac will only be
index c961f08..b1cfbaa 100644 (file)
@@ -663,6 +663,11 @@ static int vlan_dev_init(struct net_device *dev)
                                          (1<<__LINK_STATE_DORMANT))) |
                      (1<<__LINK_STATE_PRESENT);
 
+       if (real_dev->features & NETIF_F_VLAN_TSO)
+               dev->features |= real_dev->features & VLAN_TSO_FEATURES;
+       if (real_dev->features & NETIF_F_VLAN_CSUM)
+               dev->features |= real_dev->features & NETIF_F_ALL_CSUM;
+
        /* ipv6 shared card related stuff */
        dev->dev_id = real_dev->dev_id;