Skip to content

Commit 24197ee

Browse files
committed
Merge branch 'bridge-mtu'
Nikolay Aleksandrov says: ==================== net: bridge: MTU handling changes As previously discussed the recent changes break some setups and could lead to packet drops. Thus the first patch reverts the behaviour for the bridge to follow the minimum MTU but also keeps the ability to set the MTU to the maximum (out of all ports) if vlan filtering is enabled. Patch 02 is the bigger change in behaviour - we've always had trouble when configuring bridges and their MTU which is auto tuning on port events (add/del/changemtu), which means config software needs to chase it and fix it after each such event, after patch 02 we allow the user to configure any MTU (ETH_MIN/MAX limited) but once that is done the bridge stops auto tuning and relies on the user to keep the MTU correct. This should be compatible with cases that don't touch the MTU (or set it to the same value), while allowing to configure the MTU and not worry about it changing afterwards. The patches are intentionally split like this, so that if they get accepted and there are any complaints patch 02 can be reverted. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 56c03cb + 804b854 commit 24197ee

File tree

4 files changed

+25
-33
lines changed

4 files changed

+25
-33
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));
55+
br_mtu_auto_adjust(br);
5656
break;
5757

5858
case NETDEV_CHANGEADDR:

net/bridge/br_device.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,11 +224,11 @@ static void br_get_stats64(struct net_device *dev,
224224
static int br_change_mtu(struct net_device *dev, int new_mtu)
225225
{
226226
struct net_bridge *br = netdev_priv(dev);
227-
if (new_mtu > br_mtu(br))
228-
return -EINVAL;
229227

230228
dev->mtu = new_mtu;
231229

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

net/bridge/br_if.c

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

427-
static bool min_mtu(int a, int b)
428-
{
429-
return a < b ? 1 : 0;
430-
}
431-
432-
static bool max_mtu(int a, int b)
433-
{
434-
return a > b ? 1 : 0;
435-
}
436-
437427
/* MTU of the bridge pseudo-device: ETH_DATA_LEN or the minimum of the ports */
438-
static int __br_mtu(const struct net_bridge *br, bool (compare_fn)(int, int))
428+
static int br_mtu_min(const struct net_bridge *br)
439429
{
440430
const struct net_bridge_port *p;
441-
int mtu = 0;
431+
int ret_mtu = 0;
442432

443-
ASSERT_RTNL();
433+
list_for_each_entry(p, &br->port_list, list)
434+
if (!ret_mtu || ret_mtu > p->dev->mtu)
435+
ret_mtu = p->dev->mtu;
444436

445-
if (list_empty(&br->port_list))
446-
mtu = ETH_DATA_LEN;
447-
else {
448-
list_for_each_entry(p, &br->port_list, list) {
449-
if (!mtu || compare_fn(p->dev->mtu, mtu))
450-
mtu = p->dev->mtu;
451-
}
452-
}
453-
return mtu;
437+
return ret_mtu ? ret_mtu : ETH_DATA_LEN;
454438
}
455439

456-
int br_mtu(const struct net_bridge *br)
440+
void br_mtu_auto_adjust(struct net_bridge *br)
457441
{
458-
if (br_vlan_enabled(br->dev))
459-
return __br_mtu(br, max_mtu);
460-
else
461-
return __br_mtu(br, min_mtu);
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;
462453
}
463454

464455
static void br_set_gso_limits(struct net_bridge *br)
@@ -612,7 +603,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev,
612603
if (changed_addr)
613604
call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev);
614605

615-
dev_set_mtu(br->dev, br_mtu(br));
606+
br_mtu_auto_adjust(br);
616607
br_set_gso_limits(br);
617608

618609
kobject_uevent(&p->kobj, KOBJ_ADD);
@@ -659,7 +650,7 @@ int br_del_if(struct net_bridge *br, struct net_device *dev)
659650
*/
660651
del_nbp(p);
661652

662-
dev_set_mtu(br->dev, br_mtu(br));
653+
br_mtu_auto_adjust(br);
663654
br_set_gso_limits(br);
664655

665656
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);
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)