datapath: Set datapath device MTU to minimum of MTU of ports.
authorJesse Gross <jesse@nicira.com>
Mon, 1 Feb 2010 21:43:44 +0000 (16:43 -0500)
committerJesse Gross <jesse@nicira.com>
Tue, 2 Feb 2010 19:56:40 +0000 (14:56 -0500)
The MTU of the local port should be no larger than the minimum of
the MTUs of the ports attached to the bridge, overwise packets may be
dropped.  We already prevent changes to the MTU that would violate
this constraint but don't actuallly proactively set the MTU.  This
changes makes everything consistent and matches the behavior of
the bridge.

datapath/datapath.c
datapath/datapath.h
datapath/dp_notify.c

index 539859a40c908a2698d12fa9970e70f484809ac6..116fd989cd51688a83225e9203fef47c3eee71ce 100644 (file)
@@ -419,6 +419,7 @@ got_port_no:
        if (err)
                goto out_put;
 
+       set_dp_devs_mtu(dp, dev);
        dp_sysfs_add_if(dp->ports[port_no]);
 
        err = __put_user(port_no, &port.port);
@@ -1319,6 +1320,29 @@ int dp_min_mtu(const struct datapath *dp)
        return mtu ? mtu : ETH_DATA_LEN;
 }
 
+/* Sets the MTU of all datapath devices to the minimum of the ports. 'dev'
+ * is the device whose MTU may have changed.  Must be called with RTNL lock
+ * and dp_mutex. */
+void set_dp_devs_mtu(const struct datapath *dp, struct net_device *dev)
+{
+       struct net_bridge_port *p;
+       int mtu;
+
+       ASSERT_RTNL();
+
+       if (is_dp_dev(dev))
+               return;
+
+       mtu = dp_min_mtu(dp);
+
+       list_for_each_entry_rcu (p, &dp->port_list, node) {
+               struct net_device *br_dev = p->dev;
+
+               if (is_dp_dev(br_dev))
+                       dev_set_mtu(br_dev, mtu);
+       }
+}
+
 static int
 put_port(const struct net_bridge_port *p, struct odp_port __user *uop)
 {
index 7548ba26521e49b9bd63287e456c14b381a24da0..d6883db28f3d23c1519b42e262ff3a20132dae98 100644 (file)
@@ -151,6 +151,7 @@ void dp_process_received_packet(struct sk_buff *, struct net_bridge_port *);
 int dp_del_port(struct net_bridge_port *);
 int dp_output_control(struct datapath *, struct sk_buff *, int, u32 arg);
 int dp_min_mtu(const struct datapath *dp);
+void set_dp_devs_mtu(const struct datapath *dp, struct net_device *dev);
 
 struct datapath *get_dp(int dp_idx);
 
index d5a274981f9ea077ab91b570e3fe35b838bc4c5e..0278988d69a08bbc4e753e28d0ad26c05880ce92 100644 (file)
@@ -45,6 +45,14 @@ static int dp_device_event(struct notifier_block *unused, unsigned long event,
                        mutex_unlock(&dp->mutex);
                }
                break;
+
+       case NETDEV_CHANGEMTU:
+               if (!is_dp_dev(dev)) {
+                       mutex_lock(&dp->mutex);
+                       set_dp_devs_mtu(dp, dev);
+                       mutex_unlock(&dp->mutex);
+               }
+               break;
        }
        return NOTIFY_DONE;
 }