summaryrefslogtreecommitdiff
path: root/net/bridge/br_if.c
diff options
context:
space:
mode:
authorNikolay Aleksandrov <nikolay@cumulusnetworks.com>2018-03-30 13:46:18 +0300
committerDavid S. Miller <davem@davemloft.net>2018-04-01 05:19:00 +0300
commitf40aa23339e2d06b1a8daaece5a511bb1c4f704c (patch)
treec1033f88e7bf84405963f22fc664f2692aee2769 /net/bridge/br_if.c
parent56c03cbf8c4cbd413a19e8541850b0f02958fdcb (diff)
downloadlinux-f40aa23339e2d06b1a8daaece5a511bb1c4f704c.tar.xz
net: bridge: set min MTU on port events and allow user to set max
Recently the bridge was changed to automatically set maximum MTU on port events (add/del/changemtu) when vlan filtering is enabled, but that actually changes behaviour in a way which breaks some setups and can lead to packet drops. In order to still allow that maximum to be set while being compatible, we add the ability for the user to tune the bridge MTU up to the maximum when vlan filtering is enabled, but that has to be done explicitly and all port events (add/del/changemtu) lead to resetting that MTU to the minimum as before. Suggested-by: Roopa Prabhu <roopa@cumulusnetworks.com> Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/bridge/br_if.c')
-rw-r--r--net/bridge/br_if.c43
1 files changed, 14 insertions, 29 deletions
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);