aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2018-03-31 22:19:14 -0400
committerDavid S. Miller <davem@davemloft.net>2018-03-31 22:19:14 -0400
commit24197ee2102359b59044234347dd3504302fa97d (patch)
tree3c81eed86eff79013e00169ac749661b7d6b4ca4
parent56c03cbf8c4cbd413a19e8541850b0f02958fdcb (diff)
parent804b854d374e39f5f8bff9638fd274b9a9ca7d33 (diff)
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 <davem@davemloft.net>
-rw-r--r--net/bridge/br.c2
-rw-r--r--net/bridge/br_device.c4
-rw-r--r--net/bridge/br_if.c49
-rw-r--r--net/bridge/br_private.h3
4 files changed, 25 insertions, 33 deletions
diff --git a/net/bridge/br.c b/net/bridge/br.c
index 26e1616b2c90..671d13c10f6f 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
52 52
53 switch (event) { 53 switch (event) {
54 case NETDEV_CHANGEMTU: 54 case NETDEV_CHANGEMTU:
55 dev_set_mtu(br->dev, br_mtu(br)); 55 br_mtu_auto_adjust(br);
56 break; 56 break;
57 57
58 case NETDEV_CHANGEADDR: 58 case NETDEV_CHANGEADDR:
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 278fc999d355..e682a668ce57 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -224,11 +224,11 @@ static void br_get_stats64(struct net_device *dev,
224static int br_change_mtu(struct net_device *dev, int new_mtu) 224static int br_change_mtu(struct net_device *dev, int new_mtu)
225{ 225{
226 struct net_bridge *br = netdev_priv(dev); 226 struct net_bridge *br = netdev_priv(dev);
227 if (new_mtu > br_mtu(br))
228 return -EINVAL;
229 227
230 dev->mtu = new_mtu; 228 dev->mtu = new_mtu;
231 229
230 /* this flag will be cleared if the MTU was automatically adjusted */
231 br->mtu_set_by_user = true;
232#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) 232#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
233 /* remember the MTU in the rtable for PMTU */ 233 /* remember the MTU in the rtable for PMTU */
234 dst_metric_set(&br->fake_rtable.dst, RTAX_MTU, new_mtu); 234 dst_metric_set(&br->fake_rtable.dst, RTAX_MTU, new_mtu);
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 87b2afd455c7..82c1a6f430b3 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -424,41 +424,32 @@ int br_del_bridge(struct net *net, const char *name)
424 return ret; 424 return ret;
425} 425}
426 426
427static bool min_mtu(int a, int b)
428{
429 return a < b ? 1 : 0;
430}
431
432static 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 */ 427/* MTU of the bridge pseudo-device: ETH_DATA_LEN or the minimum of the ports */
438static int __br_mtu(const struct net_bridge *br, bool (compare_fn)(int, int)) 428static int br_mtu_min(const struct net_bridge *br)
439{ 429{
440 const struct net_bridge_port *p; 430 const struct net_bridge_port *p;
441 int mtu = 0; 431 int ret_mtu = 0;
442 432
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;
444 436
445 if (list_empty(&br->port_list)) 437 return ret_mtu ? ret_mtu : ETH_DATA_LEN;
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;
454} 438}
455 439
456int br_mtu(const struct net_bridge *br) 440void br_mtu_auto_adjust(struct net_bridge *br)
457{ 441{
458 if (br_vlan_enabled(br->dev)) 442 ASSERT_RTNL();
459 return __br_mtu(br, max_mtu); 443
460 else 444 /* if the bridge MTU was manually configured don't mess with it */
461 return __br_mtu(br, min_mtu); 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;
462} 453}
463 454
464static void br_set_gso_limits(struct net_bridge *br) 455static 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,
612 if (changed_addr) 603 if (changed_addr)
613 call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev); 604 call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev);
614 605
615 dev_set_mtu(br->dev, br_mtu(br)); 606 br_mtu_auto_adjust(br);
616 br_set_gso_limits(br); 607 br_set_gso_limits(br);
617 608
618 kobject_uevent(&p->kobj, KOBJ_ADD); 609 kobject_uevent(&p->kobj, KOBJ_ADD);
@@ -659,7 +650,7 @@ int br_del_if(struct net_bridge *br, struct net_device *dev)
659 */ 650 */
660 del_nbp(p); 651 del_nbp(p);
661 652
662 dev_set_mtu(br->dev, br_mtu(br)); 653 br_mtu_auto_adjust(br);
663 br_set_gso_limits(br); 654 br_set_gso_limits(br);
664 655
665 spin_lock_bh(&br->lock); 656 spin_lock_bh(&br->lock);
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 048d5b51813b..a7cb3ece5031 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -410,6 +410,7 @@ struct net_bridge {
410 int offload_fwd_mark; 410 int offload_fwd_mark;
411#endif 411#endif
412 bool neigh_suppress_enabled; 412 bool neigh_suppress_enabled;
413 bool mtu_set_by_user;
413 struct hlist_head fdb_list; 414 struct hlist_head fdb_list;
414}; 415};
415 416
@@ -578,7 +579,7 @@ int br_del_bridge(struct net *net, const char *name);
578int br_add_if(struct net_bridge *br, struct net_device *dev, 579int br_add_if(struct net_bridge *br, struct net_device *dev,
579 struct netlink_ext_ack *extack); 580 struct netlink_ext_ack *extack);
580int br_del_if(struct net_bridge *br, struct net_device *dev); 581int br_del_if(struct net_bridge *br, struct net_device *dev);
581int br_mtu(const struct net_bridge *br); 582void br_mtu_auto_adjust(struct net_bridge *br);
582netdev_features_t br_features_recompute(struct net_bridge *br, 583netdev_features_t br_features_recompute(struct net_bridge *br,
583 netdev_features_t features); 584 netdev_features_t features);
584void br_port_flags_change(struct net_bridge_port *port, unsigned long mask); 585void br_port_flags_change(struct net_bridge_port *port, unsigned long mask);