diff options
Diffstat (limited to 'net/bridge/br_if.c')
-rw-r--r-- | net/bridge/br_if.c | 35 |
1 files changed, 22 insertions, 13 deletions
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 9ba4ed65c52b..82c1a6f430b3 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -425,22 +425,31 @@ int br_del_bridge(struct net *net, const char *name) } /* MTU of the bridge pseudo-device: ETH_DATA_LEN or the minimum of the ports */ -int br_min_mtu(const struct net_bridge *br) +static int br_mtu_min(const struct net_bridge *br) { const struct net_bridge_port *p; - int mtu = 0; + int ret_mtu = 0; + list_for_each_entry(p, &br->port_list, list) + if (!ret_mtu || ret_mtu > p->dev->mtu) + ret_mtu = p->dev->mtu; + + return ret_mtu ? ret_mtu : ETH_DATA_LEN; +} + +void br_mtu_auto_adjust(struct net_bridge *br) +{ ASSERT_RTNL(); - if (list_empty(&br->port_list)) - mtu = ETH_DATA_LEN; - else { - list_for_each_entry(p, &br->port_list, list) { - if (!mtu || p->dev->mtu < mtu) - mtu = p->dev->mtu; - } - } - return mtu; + /* if the bridge MTU was manually configured don't mess with it */ + if (br->mtu_set_by_user) + return; + + /* change to the minimum MTU and clear the flag which was set by + * the bridge ndo_change_mtu callback + */ + dev_set_mtu(br->dev, br_mtu_min(br)); + br->mtu_set_by_user = false; } static void br_set_gso_limits(struct net_bridge *br) @@ -594,7 +603,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev, if (changed_addr) call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev); - dev_set_mtu(br->dev, br_min_mtu(br)); + br_mtu_auto_adjust(br); br_set_gso_limits(br); kobject_uevent(&p->kobj, KOBJ_ADD); @@ -641,7 +650,7 @@ int br_del_if(struct net_bridge *br, struct net_device *dev) */ del_nbp(p); - dev_set_mtu(br->dev, br_min_mtu(br)); + br_mtu_auto_adjust(br); br_set_gso_limits(br); spin_lock_bh(&br->lock); |