Skip to content

Commit 89470a7

Browse files
committed
libnet: bridge: ignore EINVAL when configuring bridge MTU
Since 964ab71, we explicitly set the bridge MTU if it was specified. Unfortunately, kernel <v4.17 have a check preventing us to manually set the MTU to anything greater than 1500 if no links is attached to the bridge, which is how we do things -- create the bridge, set its MTU and later on, attach veths to it. Relevant kernel commit: torvalds/linux@804b854 As we still have to support CentOS/RHEL 7 (and their old v3.10 kernels) for a few more months, we need to ignore EINVAL if the MTU is > 1500 (but <= 65535). Signed-off-by: Albin Kerouanton <[email protected]>
1 parent 7964cae commit 89470a7

2 files changed

Lines changed: 44 additions & 0 deletions

File tree

libnetwork/drivers/bridge/setup_device_linux.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ package bridge
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
67
"os"
78
"path/filepath"
9+
"syscall"
810

911
"github.com/containerd/log"
1012
"github.com/docker/docker/libnetwork/netutils"
@@ -47,6 +49,14 @@ func setupDevice(config *networkConfiguration, i *bridgeInterface) error {
4749

4850
func setupMTU(config *networkConfiguration, i *bridgeInterface) error {
4951
if err := i.nlh.LinkSetMTU(i.Link, config.Mtu); err != nil {
52+
// Before Linux v4.17, bridges couldn't be configured "manually" with an MTU greater than 1500, although it
53+
// could be autoconfigured with such a value when interfaces were added to the bridge. In that case, the
54+
// bridge MTU would be set automatically by the kernel to the lowest MTU of all interfaces attached. To keep
55+
// compatibility with older kernels, we need to discard -EINVAL.
56+
// TODO(aker): remove this once we drop support for CentOS/RHEL 7.
57+
if config.Mtu > 1500 && config.Mtu <= 0xFFFF && errors.Is(err, syscall.EINVAL) {
58+
return nil
59+
}
5060
log.G(context.TODO()).WithError(err).Errorf("Failed to set bridge MTU %s via netlink", config.BridgeName)
5161
return err
5262
}

libnetwork/drivers/bridge/setup_device_linux_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ package bridge
33
import (
44
"bytes"
55
"net"
6+
"syscall"
67
"testing"
78

89
"github.com/docker/docker/internal/testutils/netnsutils"
910
"github.com/docker/docker/libnetwork/netutils"
1011
"github.com/vishvananda/netlink"
12+
"gotest.tools/v3/assert"
1113
)
1214

1315
func TestSetupNewBridge(t *testing.T) {
@@ -92,3 +94,35 @@ func TestGenerateRandomMAC(t *testing.T) {
9294
t.Fatalf("Generated twice the same MAC address %v", mac1)
9395
}
9496
}
97+
98+
func TestMTUBiggerThan1500(t *testing.T) {
99+
defer netnsutils.SetupTestOSContext(t)()
100+
101+
nh, err := netlink.NewHandle()
102+
if err != nil {
103+
t.Fatal(err)
104+
}
105+
defer nh.Close()
106+
107+
config := &networkConfiguration{BridgeName: DefaultBridgeName, Mtu: 9000}
108+
br := &bridgeInterface{nlh: nh}
109+
110+
assert.NilError(t, setupDevice(config, br))
111+
assert.NilError(t, setupMTU(config, br))
112+
}
113+
114+
func TestMTUBiggerThan64K(t *testing.T) {
115+
defer netnsutils.SetupTestOSContext(t)()
116+
117+
nh, err := netlink.NewHandle()
118+
if err != nil {
119+
t.Fatal(err)
120+
}
121+
defer nh.Close()
122+
123+
config := &networkConfiguration{BridgeName: DefaultBridgeName, Mtu: 65536}
124+
br := &bridgeInterface{nlh: nh}
125+
126+
assert.NilError(t, setupDevice(config, br))
127+
assert.ErrorIs(t, setupMTU(config, br), syscall.EINVAL)
128+
}

0 commit comments

Comments
 (0)