aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChas Williams <3chas3@gmail.com>2018-03-22 11:34:06 -0400
committerDavid S. Miller <davem@davemloft.net>2018-03-23 12:17:30 -0400
commit419d14af9e07fb5ca32b1b1614793c6b1e242152 (patch)
tree4890f2aedb3f31dbf9c32f0d90b07f0781ced4e4
parentbda7fab54828bbef2164bb23c0f6b1a7d05cc718 (diff)
bridge: Allow max MTU when multiple VLANs present
If the bridge is allowing multiple VLANs, some VLANs may have different MTUs. Instead of choosing the minimum MTU for the bridge interface, choose the maximum MTU of the bridge members. With this the user only needs to set a larger MTU on the member ports that are participating in the large MTU VLANS. Signed-off-by: Chas Williams <3chas3@gmail.com> Reviewed-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> Acked-by: Roopa Prabhu <roopa@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/bridge/br.c2
-rw-r--r--net/bridge/br_device.c2
-rw-r--r--net/bridge/br_if.c26
-rw-r--r--net/bridge/br_private.h2
4 files changed, 25 insertions, 7 deletions
diff --git a/net/bridge/br.c b/net/bridge/br.c
index 7770481a6506..a3f95ab9d6a3 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_min_mtu(br)); 55 dev_set_mtu(br->dev, br_mtu(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 1285ca30ab0a..278fc999d355 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -224,7 +224,7 @@ 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_min_mtu(br)) 227 if (new_mtu > br_mtu(br))
228 return -EINVAL; 228 return -EINVAL;
229 229
230 dev->mtu = new_mtu; 230 dev->mtu = new_mtu;
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 9ba4ed65c52b..48dc4d2e2be3 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -424,8 +424,18 @@ 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
427/* MTU of the bridge pseudo-device: ETH_DATA_LEN or the minimum of the ports */ 437/* MTU of the bridge pseudo-device: ETH_DATA_LEN or the minimum of the ports */
428int br_min_mtu(const struct net_bridge *br) 438static int __br_mtu(const struct net_bridge *br, bool (compare_fn)(int, int))
429{ 439{
430 const struct net_bridge_port *p; 440 const struct net_bridge_port *p;
431 int mtu = 0; 441 int mtu = 0;
@@ -436,13 +446,21 @@ int br_min_mtu(const struct net_bridge *br)
436 mtu = ETH_DATA_LEN; 446 mtu = ETH_DATA_LEN;
437 else { 447 else {
438 list_for_each_entry(p, &br->port_list, list) { 448 list_for_each_entry(p, &br->port_list, list) {
439 if (!mtu || p->dev->mtu < mtu) 449 if (!mtu || compare_fn(p->dev->mtu, mtu))
440 mtu = p->dev->mtu; 450 mtu = p->dev->mtu;
441 } 451 }
442 } 452 }
443 return mtu; 453 return mtu;
444} 454}
445 455
456int br_mtu(const struct net_bridge *br)
457{
458 if (br->vlan_enabled)
459 return __br_mtu(br, max_mtu);
460 else
461 return __br_mtu(br, min_mtu);
462}
463
446static void br_set_gso_limits(struct net_bridge *br) 464static void br_set_gso_limits(struct net_bridge *br)
447{ 465{
448 unsigned int gso_max_size = GSO_MAX_SIZE; 466 unsigned int gso_max_size = GSO_MAX_SIZE;
@@ -594,7 +612,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev,
594 if (changed_addr) 612 if (changed_addr)
595 call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev); 613 call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev);
596 614
597 dev_set_mtu(br->dev, br_min_mtu(br)); 615 dev_set_mtu(br->dev, br_mtu(br));
598 br_set_gso_limits(br); 616 br_set_gso_limits(br);
599 617
600 kobject_uevent(&p->kobj, KOBJ_ADD); 618 kobject_uevent(&p->kobj, KOBJ_ADD);
@@ -641,7 +659,7 @@ int br_del_if(struct net_bridge *br, struct net_device *dev)
641 */ 659 */
642 del_nbp(p); 660 del_nbp(p);
643 661
644 dev_set_mtu(br->dev, br_min_mtu(br)); 662 dev_set_mtu(br->dev, br_mtu(br));
645 br_set_gso_limits(br); 663 br_set_gso_limits(br);
646 664
647 spin_lock_bh(&br->lock); 665 spin_lock_bh(&br->lock);
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 8e13a64d8c99..048d5b51813b 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -578,7 +578,7 @@ int br_del_bridge(struct net *net, const char *name);
578int br_add_if(struct net_bridge *br, struct net_device *dev, 578int br_add_if(struct net_bridge *br, struct net_device *dev,
579 struct netlink_ext_ack *extack); 579 struct netlink_ext_ack *extack);
580int br_del_if(struct net_bridge *br, struct net_device *dev); 580int br_del_if(struct net_bridge *br, struct net_device *dev);
581int br_min_mtu(const struct net_bridge *br); 581int br_mtu(const struct net_bridge *br);
582netdev_features_t br_features_recompute(struct net_bridge *br, 582netdev_features_t br_features_recompute(struct net_bridge *br,
583 netdev_features_t features); 583 netdev_features_t features);
584void br_port_flags_change(struct net_bridge_port *port, unsigned long mask); 584void br_port_flags_change(struct net_bridge_port *port, unsigned long mask);