aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Gross <jesse@nicira.com>2010-02-01 16:43:44 -0500
committerJesse Gross <jesse@nicira.com>2010-02-02 14:56:40 -0500
commita778696338b85b86b31b9ec7d1a4daeda430aa8b (patch)
treed0d9f98d7a2f8ebd005fba4131fcfa0cc5d3f846
parent65272b911471662a24886f571b1fb2779c90ebaf (diff)
datapath: Set datapath device MTU to minimum of MTU of ports.
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.
-rw-r--r--datapath/datapath.c24
-rw-r--r--datapath/datapath.h1
-rw-r--r--datapath/dp_notify.c8
3 files changed, 33 insertions, 0 deletions
diff --git a/datapath/datapath.c b/datapath/datapath.c
index 539859a4..116fd989 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -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)
{
diff --git a/datapath/datapath.h b/datapath/datapath.h
index 7548ba26..d6883db2 100644
--- a/datapath/datapath.h
+++ b/datapath/datapath.h
@@ -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);
diff --git a/datapath/dp_notify.c b/datapath/dp_notify.c
index d5a27498..0278988d 100644
--- a/datapath/dp_notify.c
+++ b/datapath/dp_notify.c
@@ -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;
}