]> git.hungrycats.org Git - linux/commitdiff
[BRIDGE]: Support different MTU sizes.
authorStephen Hemminger <shemminger@osdl.org>
Fri, 9 Jul 2004 09:37:16 +0000 (02:37 -0700)
committerDavid S. Miller <davem@nuts.davemloft.net>
Fri, 9 Jul 2004 09:37:16 +0000 (02:37 -0700)
This patch adds support for different size MTU's to bridging.
It is useful for bridging Ethernet's with jumbo frames, etc.

The mtu of the bridge pseudo-device is maintained as the minimum
of all the underlying ports.  And when forwarding a frame through
the bridge, it will drop the frame if the outgoing port's MTU
is less than the frame size (as per 802 standard).

Signed-off-by: Stephen Hemminger <shemminger@osdl.org>
Signed-off-by: David S. Miller <davem@redhat.com>
net/bridge/br_device.c
net/bridge/br_forward.c
net/bridge/br_if.c
net/bridge/br_notify.c
net/bridge/br_private.h

index b7e6adc0bd9be52dcc0183f2a325e27fd4098475..e91f80f972ff3f3736f62d16c1e1a5b83ee2fd50 100644 (file)
@@ -89,6 +89,15 @@ static int br_dev_stop(struct net_device *dev)
        return 0;
 }
 
+static int br_change_mtu(struct net_device *dev, int new_mtu)
+{
+       if ((new_mtu < 68) || new_mtu > br_min_mtu(dev->priv))
+               return -EINVAL;
+
+       dev->mtu = new_mtu;
+       return 0;
+}
+
 static int br_dev_accept_fastpath(struct net_device *dev, struct dst_entry *dst)
 {
        return -1;
@@ -105,6 +114,7 @@ void br_dev_setup(struct net_device *dev)
        dev->hard_start_xmit = br_dev_xmit;
        dev->open = br_dev_open;
        dev->set_multicast_list = br_dev_set_multicast_list;
+       dev->change_mtu = br_change_mtu;
        dev->destructor = free_netdev;
        SET_MODULE_OWNER(dev);
        dev->stop = br_dev_stop;
index 1589763867d0dee139c3250a9973833d0b21818d..fd5fa75a3525fb43c052e058a81eeb43d2f98b6d 100644 (file)
@@ -23,6 +23,7 @@ static inline int should_deliver(const struct net_bridge_port *p,
                                 const struct sk_buff *skb)
 {
        if (skb->dev == p->dev ||
+           skb->len > p->dev->mtu ||
            p->state != BR_STATE_FORWARDING)
                return 0;
 
index 6bb2ed24718fd3c6e948debaca6361c1a6aa2a9b..092d45163644925006545ff796ae0ae0d1f2fee7 100644 (file)
@@ -295,6 +295,24 @@ int br_del_bridge(const char *name)
        return ret;
 }
 
+int br_min_mtu(const struct net_bridge *br)
+{
+       const struct net_bridge_port *p;
+       int mtu = 0;
+
+       ASSERT_RTNL();
+
+       if (list_empty(&br->port_list))
+               mtu = 1500;
+       else {
+               list_for_each_entry(p, &br->port_list, list) {
+                       if (!mtu  || p->dev->mtu < mtu)
+                               mtu = p->dev->mtu;
+               }
+       }
+       return mtu;
+}
+
 /* called with RTNL */
 int br_add_if(struct net_bridge *br, struct net_device *dev)
 {
@@ -328,6 +346,8 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
                if ((br->dev->flags & IFF_UP) && (dev->flags & IFF_UP))
                        br_stp_enable_port(p);
                spin_unlock_bh(&br->lock);
+
+               br->dev->mtu = br_min_mtu(br);
        }
 
        return err;
index c59335e3b49b126ca6f52f6fc9960d5dbb6a00b7..5c88a71b85e3cf0af0b1a400a06f67f4b09de29d 100644 (file)
@@ -47,6 +47,10 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
                spin_unlock_bh(&br->lock);
                break;
 
+       case NETDEV_CHANGEMTU:
+               br->dev->mtu = br_min_mtu(br);
+               break;
+
        case NETDEV_DOWN:
                if (br->dev->flags & IFF_UP) {
                        spin_lock_bh(&br->lock);
index 7cfb82b762525fa2c46736e33a6fb03043612866..1064d4c68c24121396a78e2f88d50563e50050e0 100644 (file)
@@ -168,6 +168,7 @@ extern int br_add_if(struct net_bridge *br,
              struct net_device *dev);
 extern int br_del_if(struct net_bridge *br,
              struct net_device *dev);
+extern int br_min_mtu(const struct net_bridge *br);
 
 /* br_input.c */
 extern int br_handle_frame_finish(struct sk_buff *skb);