diff --git a/net/bridge/br.c b/net/bridge/br.c index 26e1616b2c90..565ff055813b 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c @@ -52,7 +52,7 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v switch (event) { case NETDEV_CHANGEMTU: - dev_set_mtu(br->dev, br_mtu(br)); + dev_set_mtu(br->dev, br_mtu(br, false)); break; case NETDEV_CHANGEADDR: diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 278fc999d355..edb9967eb165 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -224,7 +224,8 @@ static void br_get_stats64(struct net_device *dev, static int br_change_mtu(struct net_device *dev, int new_mtu) { struct net_bridge *br = netdev_priv(dev); - if (new_mtu > br_mtu(br)) + + if (new_mtu > br_mtu(br, br_vlan_enabled(dev))) return -EINVAL; dev->mtu = new_mtu; diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 87b2afd455c7..7d5dc5a91084 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -424,41 +424,26 @@ int br_del_bridge(struct net *net, const char *name) return ret; } -static bool min_mtu(int a, int b) -{ - return a < b ? 1 : 0; -} - -static bool max_mtu(int a, int b) -{ - return a > b ? 1 : 0; -} - -/* MTU of the bridge pseudo-device: ETH_DATA_LEN or the minimum of the ports */ -static int __br_mtu(const struct net_bridge *br, bool (compare_fn)(int, int)) +/* MTU of the bridge pseudo-device: ETH_DATA_LEN if there are no ports, the + * minimum of the ports if @max is false or the maximum if it's true + */ +int br_mtu(const struct net_bridge *br, bool max) { const struct net_bridge_port *p; - int mtu = 0; + int ret_mtu = 0; ASSERT_RTNL(); - if (list_empty(&br->port_list)) - mtu = ETH_DATA_LEN; - else { - list_for_each_entry(p, &br->port_list, list) { - if (!mtu || compare_fn(p->dev->mtu, mtu)) - mtu = p->dev->mtu; + list_for_each_entry(p, &br->port_list, list) { + if (!max) { + if (!ret_mtu || ret_mtu > p->dev->mtu) + ret_mtu = p->dev->mtu; + } else if (p->dev->mtu > ret_mtu) { + ret_mtu = p->dev->mtu; } } - return mtu; -} -int br_mtu(const struct net_bridge *br) -{ - if (br_vlan_enabled(br->dev)) - return __br_mtu(br, max_mtu); - else - return __br_mtu(br, min_mtu); + return ret_mtu ? ret_mtu : ETH_DATA_LEN; } static void br_set_gso_limits(struct net_bridge *br) @@ -612,7 +597,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_mtu(br)); + dev_set_mtu(br->dev, br_mtu(br, false)); br_set_gso_limits(br); kobject_uevent(&p->kobj, KOBJ_ADD); @@ -659,7 +644,7 @@ int br_del_if(struct net_bridge *br, struct net_device *dev) */ del_nbp(p); - dev_set_mtu(br->dev, br_mtu(br)); + dev_set_mtu(br->dev, br_mtu(br, false)); br_set_gso_limits(br); spin_lock_bh(&br->lock); diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 048d5b51813b..586f84b9670d 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -578,7 +578,7 @@ int br_del_bridge(struct net *net, const char *name); int br_add_if(struct net_bridge *br, struct net_device *dev, struct netlink_ext_ack *extack); int br_del_if(struct net_bridge *br, struct net_device *dev); -int br_mtu(const struct net_bridge *br); +int br_mtu(const struct net_bridge *br, bool max); netdev_features_t br_features_recompute(struct net_bridge *br, netdev_features_t features); void br_port_flags_change(struct net_bridge_port *port, unsigned long mask);