From 1dcf111b1cb66fe1f3ed2e45f66ab6f5659a6527 Mon Sep 17 00:00:00 2001 From: Justin Pettit Date: Sat, 1 Aug 2009 00:09:56 -0700 Subject: [PATCH] datapath: Support jumbo frames in the datapath device 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 | 23 +++++++++++++++++++++++ datapath/datapath.h | 1 + datapath/dp_dev.c | 10 ++++++++++ 3 files changed, 34 insertions(+) diff --git a/datapath/datapath.c b/datapath/datapath.c index 5e1a352cc..43d96fbde 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -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) { diff --git a/datapath/datapath.h b/datapath/datapath.h index 455580f06..a03597d8c 100644 --- a/datapath/datapath.h +++ b/datapath/datapath.h @@ -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); diff --git a/datapath/dp_dev.c b/datapath/dp_dev.c index 3902a8c5f..422af0205 100644 --- a/datapath/dp_dev.c +++ b/datapath/dp_dev.c @@ -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; -- 2.39.5