Skip to content

Commit f40aa23

Browse files
Nikolay Aleksandrovdavem330
authored andcommitted
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 <[email protected]> Signed-off-by: Nikolay Aleksandrov <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 56c03cb commit f40aa23

File tree

4 files changed

+18
-32
lines changed

4 files changed

+18
-32
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+
dev_set_mtu(br->dev, br_mtu(br, false));
5656
break;
5757

5858
case NETDEV_CHANGEADDR:

net/bridge/br_device.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,8 @@ 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))
227+
228+
if (new_mtu > br_mtu(br, br_vlan_enabled(dev)))
228229
return -EINVAL;
229230

230231
dev->mtu = new_mtu;

net/bridge/br_if.c

Lines changed: 14 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -424,41 +424,26 @@ 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-
437-
/* 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))
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)
439431
{
440432
const struct net_bridge_port *p;
441-
int mtu = 0;
433+
int ret_mtu = 0;
442434

443435
ASSERT_RTNL();
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;
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) {
442+
ret_mtu = p->dev->mtu;
451443
}
452444
}
453-
return mtu;
454-
}
455445

456-
int br_mtu(const struct net_bridge *br)
457-
{
458-
if (br_vlan_enabled(br->dev))
459-
return __br_mtu(br, max_mtu);
460-
else
461-
return __br_mtu(br, min_mtu);
446+
return ret_mtu ? ret_mtu : ETH_DATA_LEN;
462447
}
463448

464449
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,
612597
if (changed_addr)
613598
call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev);
614599

615-
dev_set_mtu(br->dev, br_mtu(br));
600+
dev_set_mtu(br->dev, br_mtu(br, false));
616601
br_set_gso_limits(br);
617602

618603
kobject_uevent(&p->kobj, KOBJ_ADD);
@@ -659,7 +644,7 @@ int br_del_if(struct net_bridge *br, struct net_device *dev)
659644
*/
660645
del_nbp(p);
661646

662-
dev_set_mtu(br->dev, br_mtu(br));
647+
dev_set_mtu(br->dev, br_mtu(br, false));
663648
br_set_gso_limits(br);
664649

665650
spin_lock_bh(&br->lock);

net/bridge/br_private.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -578,7 +578,7 @@ int br_del_bridge(struct net *net, const char *name);
578578
int br_add_if(struct net_bridge *br, struct net_device *dev,
579579
struct netlink_ext_ack *extack);
580580
int br_del_if(struct net_bridge *br, struct net_device *dev);
581-
int br_mtu(const struct net_bridge *br);
581+
int br_mtu(const struct net_bridge *br, bool max);
582582
netdev_features_t br_features_recompute(struct net_bridge *br,
583583
netdev_features_t features);
584584
void br_port_flags_change(struct net_bridge_port *port, unsigned long mask);

0 commit comments

Comments
 (0)