Skip to content

Commit 804b854

Browse files
Nikolay Aleksandrovdavem330
authored andcommitted
net: bridge: disable bridge MTU auto tuning if it was set manually
As Roopa noted today the biggest source of problems when configuring bridge and ports is that the bridge MTU keeps changing automatically on port events (add/del/changemtu). That leads to inconsistent behaviour and network config software needs to chase the MTU and fix it on each such event. Let's improve on that situation and allow for the user to set any MTU within ETH_MIN/MAX limits, but once manually configured it is the user's responsibility to keep it correct afterwards. In case the MTU isn't manually set - the behaviour reverts to the previous and the bridge follows the minimum MTU. Signed-off-by: Nikolay Aleksandrov <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent f40aa23 commit 804b854

File tree

4 files changed

+26
-20
lines changed

4 files changed

+26
-20
lines changed

net/bridge/br.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
5252

5353
switch (event) {
5454
case NETDEV_CHANGEMTU:
55-
dev_set_mtu(br->dev, br_mtu(br, false));
55+
br_mtu_auto_adjust(br);
5656
break;
5757

5858
case NETDEV_CHANGEADDR:

net/bridge/br_device.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -225,11 +225,10 @@ static int br_change_mtu(struct net_device *dev, int new_mtu)
225225
{
226226
struct net_bridge *br = netdev_priv(dev);
227227

228-
if (new_mtu > br_mtu(br, br_vlan_enabled(dev)))
229-
return -EINVAL;
230-
231228
dev->mtu = new_mtu;
232229

230+
/* this flag will be cleared if the MTU was automatically adjusted */
231+
br->mtu_set_by_user = true;
233232
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
234233
/* remember the MTU in the rtable for PMTU */
235234
dst_metric_set(&br->fake_rtable.dst, RTAX_MTU, new_mtu);

net/bridge/br_if.c

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -424,28 +424,34 @@ int br_del_bridge(struct net *net, const char *name)
424424
return ret;
425425
}
426426

427-
/* MTU of the bridge pseudo-device: ETH_DATA_LEN if there are no ports, the
428-
* minimum of the ports if @max is false or the maximum if it's true
429-
*/
430-
int br_mtu(const struct net_bridge *br, bool max)
427+
/* MTU of the bridge pseudo-device: ETH_DATA_LEN or the minimum of the ports */
428+
static int br_mtu_min(const struct net_bridge *br)
431429
{
432430
const struct net_bridge_port *p;
433431
int ret_mtu = 0;
434432

435-
ASSERT_RTNL();
436-
437-
list_for_each_entry(p, &br->port_list, list) {
438-
if (!max) {
439-
if (!ret_mtu || ret_mtu > p->dev->mtu)
440-
ret_mtu = p->dev->mtu;
441-
} else if (p->dev->mtu > ret_mtu) {
433+
list_for_each_entry(p, &br->port_list, list)
434+
if (!ret_mtu || ret_mtu > p->dev->mtu)
442435
ret_mtu = p->dev->mtu;
443-
}
444-
}
445436

446437
return ret_mtu ? ret_mtu : ETH_DATA_LEN;
447438
}
448439

440+
void br_mtu_auto_adjust(struct net_bridge *br)
441+
{
442+
ASSERT_RTNL();
443+
444+
/* if the bridge MTU was manually configured don't mess with it */
445+
if (br->mtu_set_by_user)
446+
return;
447+
448+
/* change to the minimum MTU and clear the flag which was set by
449+
* the bridge ndo_change_mtu callback
450+
*/
451+
dev_set_mtu(br->dev, br_mtu_min(br));
452+
br->mtu_set_by_user = false;
453+
}
454+
449455
static void br_set_gso_limits(struct net_bridge *br)
450456
{
451457
unsigned int gso_max_size = GSO_MAX_SIZE;
@@ -597,7 +603,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev,
597603
if (changed_addr)
598604
call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev);
599605

600-
dev_set_mtu(br->dev, br_mtu(br, false));
606+
br_mtu_auto_adjust(br);
601607
br_set_gso_limits(br);
602608

603609
kobject_uevent(&p->kobj, KOBJ_ADD);
@@ -644,7 +650,7 @@ int br_del_if(struct net_bridge *br, struct net_device *dev)
644650
*/
645651
del_nbp(p);
646652

647-
dev_set_mtu(br->dev, br_mtu(br, false));
653+
br_mtu_auto_adjust(br);
648654
br_set_gso_limits(br);
649655

650656
spin_lock_bh(&br->lock);

net/bridge/br_private.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,7 @@ struct net_bridge {
410410
int offload_fwd_mark;
411411
#endif
412412
bool neigh_suppress_enabled;
413+
bool mtu_set_by_user;
413414
struct hlist_head fdb_list;
414415
};
415416

@@ -578,7 +579,7 @@ int br_del_bridge(struct net *net, const char *name);
578579
int br_add_if(struct net_bridge *br, struct net_device *dev,
579580
struct netlink_ext_ack *extack);
580581
int br_del_if(struct net_bridge *br, struct net_device *dev);
581-
int br_mtu(const struct net_bridge *br, bool max);
582+
void br_mtu_auto_adjust(struct net_bridge *br);
582583
netdev_features_t br_features_recompute(struct net_bridge *br,
583584
netdev_features_t features);
584585
void br_port_flags_change(struct net_bridge_port *port, unsigned long mask);

0 commit comments

Comments
 (0)