[BRIDGE]: set features based on enslaved devices
Stephen Hemminger [Sun, 29 May 2005 21:15:17 +0000 (14:15 -0700)]
Make features of the bridge pseudo-device be a subset of the underlying
devices.  Motivated by Xen and others who use bridging to do failover.

Signed-off-by: Catalin BOIE <catab at umrella.ro>
Signed-off-by: Stephen Hemminger <shemminger@osdl.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

net/bridge/br_device.c
net/bridge/br_if.c
net/bridge/br_notify.c
net/bridge/br_private.h

index d9b72fd..f564ee9 100644 (file)
 
 static struct net_device_stats *br_dev_get_stats(struct net_device *dev)
 {
-       struct net_bridge *br;
-
-       br = dev->priv;
-
+       struct net_bridge *br = netdev_priv(dev);
        return &br->statistics;
 }
 
@@ -54,9 +51,11 @@ int br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
 
 static int br_dev_open(struct net_device *dev)
 {
-       netif_start_queue(dev);
+       struct net_bridge *br = netdev_priv(dev);
 
-       br_stp_enable_bridge(dev->priv);
+       br_features_recompute(br);
+       netif_start_queue(dev);
+       br_stp_enable_bridge(br);
 
        return 0;
 }
@@ -67,7 +66,7 @@ static void br_dev_set_multicast_list(struct net_device *dev)
 
 static int br_dev_stop(struct net_device *dev)
 {
-       br_stp_disable_bridge(dev->priv);
+       br_stp_disable_bridge(netdev_priv(dev));
 
        netif_stop_queue(dev);
 
@@ -76,7 +75,7 @@ static int br_dev_stop(struct net_device *dev)
 
 static int br_change_mtu(struct net_device *dev, int new_mtu)
 {
-       if ((new_mtu < 68) || new_mtu > br_min_mtu(dev->priv))
+       if (new_mtu < 68 || new_mtu > br_min_mtu(netdev_priv(dev)))
                return -EINVAL;
 
        dev->mtu = new_mtu;
index 69872bf..91bb895 100644 (file)
@@ -314,6 +314,28 @@ int br_min_mtu(const struct net_bridge *br)
        return mtu;
 }
 
+/*
+ * Recomputes features using slave's features
+ */
+void br_features_recompute(struct net_bridge *br)
+{
+       struct net_bridge_port *p;
+       unsigned long features, checksum;
+
+       features = NETIF_F_SG | NETIF_F_FRAGLIST 
+               | NETIF_F_HIGHDMA | NETIF_F_TSO;
+       checksum = NETIF_F_IP_CSUM;     /* least commmon subset */
+
+       list_for_each_entry(p, &br->port_list, list) {
+               if (!(p->dev->features 
+                     & (NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM)))
+                       checksum = 0;
+               features &= p->dev->features;
+       }
+
+       br->dev->features = features | checksum | NETIF_F_LLTX;
+}
+
 /* called with RTNL */
 int br_add_if(struct net_bridge *br, struct net_device *dev)
 {
@@ -368,6 +390,7 @@ int br_del_if(struct net_bridge *br, struct net_device *dev)
 
        spin_lock_bh(&br->lock);
        br_stp_recalculate_bridge_id(br);
+       br_features_recompute(br);
        spin_unlock_bh(&br->lock);
 
        return 0;
index f8fb49e..917311c 100644 (file)
@@ -65,6 +65,15 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
                }
                break;
 
+       case NETDEV_FEAT_CHANGE:
+               if (br->dev->flags & IFF_UP) 
+                       br_features_recompute(br);
+
+               /* could do recursive feature change notification
+                * but who would care?? 
+                */
+               break;
+
        case NETDEV_DOWN:
                if (br->dev->flags & IFF_UP)
                        br_stp_disable_port(p);
index 54d63f1..bdf95a7 100644 (file)
@@ -174,6 +174,7 @@ extern int br_add_if(struct net_bridge *br,
 extern int br_del_if(struct net_bridge *br,
              struct net_device *dev);
 extern int br_min_mtu(const struct net_bridge *br);
+extern void br_features_recompute(struct net_bridge *br);
 
 /* br_input.c */
 extern int br_handle_frame_finish(struct sk_buff *skb);