From 964ab7158c7b8e387cdce0fb2fc451ce1e132a3e Mon Sep 17 00:00:00 2001 From: Rob Murray Date: Fri, 24 Nov 2023 17:35:01 +0000 Subject: [PATCH] Explicitly set MTU on bridge devices. This is purely cosmetic - if a non-default MTU is configured, the bridge will have the default MTU=1500 until a container's 'veth' is connected and an MTU is set on the veth. That's a disconcerting, it looks like the config has been ignored - so, set the bridge's MTU explicitly. Fixes #37937 Signed-off-by: Rob Murray --- integration/network/network_test.go | 11 ++++++++++- libnetwork/drivers/bridge/bridge_linux.go | 8 ++++++++ libnetwork/drivers/bridge/setup_device_linux.go | 8 ++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/integration/network/network_test.go b/integration/network/network_test.go index 154c08d931..3b80f37f9f 100644 --- a/integration/network/network_test.go +++ b/integration/network/network_test.go @@ -240,7 +240,7 @@ func TestDefaultNetworkOpts(t *testing.T) { // Create a new network networkName := "testnet" - network.CreateNoError(ctx, t, c, networkName, func(create *types.NetworkCreate) { + networkId := network.CreateNoError(ctx, t, c, networkName, func(create *types.NetworkCreate) { if tc.configFrom { create.ConfigFrom = &ntypes.ConfigReference{ Network: "from-net", @@ -249,6 +249,15 @@ func TestDefaultNetworkOpts(t *testing.T) { }) defer c.NetworkRemove(ctx, networkName) + // Check the MTU of the bridge itself, before any devices are connected. (The + // bridge's MTU will be set to the minimum MTU of anything connected to it, but + // it's set explicitly on the bridge anyway - so it doesn't look like the option + // was ignored.) + cmd := exec.Command("ip", "link", "show", "br-"+networkId[:12]) + output, err := cmd.CombinedOutput() + assert.NilError(t, err) + assert.Check(t, is.Contains(string(output), fmt.Sprintf(" mtu %d ", tc.mtu)), "Bridge MTU should have been set to %d", tc.mtu) + // Start a container to inspect the MTU of its network interface id1 := container.Run(ctx, t, c, container.WithNetworkMode(networkName)) defer c.ContainerRemove(ctx, id1, containertypes.RemoveOptions{Force: true}) diff --git a/libnetwork/drivers/bridge/bridge_linux.go b/libnetwork/drivers/bridge/bridge_linux.go index f438e5480c..a9b54cfce3 100644 --- a/libnetwork/drivers/bridge/bridge_linux.go +++ b/libnetwork/drivers/bridge/bridge_linux.go @@ -735,6 +735,14 @@ func (d *driver) createNetwork(config *networkConfiguration) (err error) { bridgeSetup.queueStep(setupDefaultSysctl) } + // Always set the bridge's MTU if specified. This is purely cosmetic; a bridge's + // MTU is the min MTU of device connected to it, and MTU will be set on each + // 'veth'. But, for a non-default MTU, the bridge's MTU will look wrong until a + // container is attached. + if config.Mtu > 0 { + bridgeSetup.queueStep(setupMTU) + } + // Even if a bridge exists try to setup IPv4. bridgeSetup.queueStep(setupBridgeIPv4) diff --git a/libnetwork/drivers/bridge/setup_device_linux.go b/libnetwork/drivers/bridge/setup_device_linux.go index a90b8cea1d..050aaa1710 100644 --- a/libnetwork/drivers/bridge/setup_device_linux.go +++ b/libnetwork/drivers/bridge/setup_device_linux.go @@ -45,6 +45,14 @@ func setupDevice(config *networkConfiguration, i *bridgeInterface) error { return nil } +func setupMTU(config *networkConfiguration, i *bridgeInterface) error { + if err := i.nlh.LinkSetMTU(i.Link, config.Mtu); err != nil { + log.G(context.TODO()).WithError(err).Errorf("Failed to set bridge MTU %s via netlink", config.BridgeName) + return err + } + return nil +} + func setupDefaultSysctl(config *networkConfiguration, i *bridgeInterface) error { // Disable IPv6 router advertisements originating on the bridge sysPath := filepath.Join("/proc/sys/net/ipv6/conf/", config.BridgeName, "accept_ra")