datapath: Support jumbo frames in the datapath device
authorJustin Pettit <jpettit@nicira.com>
Sat, 1 Aug 2009 07:09:56 +0000 (00:09 -0700)
committerJustin Pettit <jpettit@nicira.com>
Mon, 3 Aug 2009 20:29:22 +0000 (13:29 -0700)
The datapath has no problems switching jumbo frames (frames with a payload
greater than 1500 bytes), but it has not supported sending and receiving
them to the device itself.  With this commit, the MTU can be set as large
as the minimum MTU size of the devices that are directly attached, or 1500
bytes if there are none.  This mimics the behavior of the Linux bridge.

Feature #1736

datapath/datapath.c
datapath/datapath.h
datapath/dp_dev.c

index 5e1a352ccbd538b03caa223d663ad90179c90748..43d96fbdecb58eb85f85092cb68c015cf3f31594 100644 (file)
@@ -1184,6 +1184,29 @@ get_dp_stats(struct datapath *dp, struct odp_stats __user *statsp)
        return copy_to_user(statsp, &stats, sizeof stats) ? -EFAULT : 0;
 }
 
+/* MTU of the dp pseudo-device: ETH_DATA_LEN or the minimum of the ports */
+int dp_min_mtu(const struct datapath *dp)
+{
+       struct net_bridge_port *p;
+       int mtu = 0;
+
+       ASSERT_RTNL();
+
+       list_for_each_entry_rcu (p, &dp->port_list, node) {
+               struct net_device *dev = p->dev;
+
+               /* Skip any internal ports, since that's what we're trying to
+                * set. */
+               if (is_dp_dev(dev))
+                       continue;
+
+               if (!mtu || dev->mtu < mtu)
+                       mtu = dev->mtu;
+       }
+
+       return mtu ? mtu : ETH_DATA_LEN;
+}
+
 static int
 put_port(const struct net_bridge_port *p, struct odp_port __user *uop)
 {
index 455580f06f4bcf9a50500b9c54eb482b41c48597..a03597d8ca309e1ecae4c9ed2fb18753dd7b5387 100644 (file)
@@ -122,6 +122,7 @@ int dp_table_foreach(struct dp_table *table,
 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);
 
 struct datapath *get_dp(int dp_idx);
 
index 3902a8c5f2eb21e41070eeeb8dd777f63a421b08..422af0205d55466f2483f7799c93f9a09bd2657b 100644 (file)
@@ -130,6 +130,15 @@ static struct ethtool_ops dp_ethtool_ops = {
        .get_tso = ethtool_op_get_tso,
 };
 
+static int dp_dev_change_mtu(struct net_device *dev, int new_mtu)
+{
+       if (new_mtu < 68 || new_mtu > dp_min_mtu(dp_dev_get_dp(dev)))
+               return -EINVAL;
+
+       dev->mtu = new_mtu;
+       return 0;
+}
+
 static int dp_dev_init(struct net_device *netdev)
 {
        struct dp_dev *dp_dev = dp_dev_priv(netdev);
@@ -162,6 +171,7 @@ do_setup(struct net_device *netdev)
        netdev->stop = dp_dev_stop;
        netdev->tx_queue_len = 0;
        netdev->set_mac_address = dp_dev_mac_addr;
+       netdev->change_mtu = dp_dev_change_mtu;
        netdev->init = dp_dev_init;
        netdev->destructor = dp_dev_free;