Skip to content

Commit

Permalink
libnet: bridge: ignore EINVAL when configuring bridge MTU
Browse files Browse the repository at this point in the history
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 <albinker@gmail.com>
  • Loading branch information
akerouanton committed Feb 2, 2024
1 parent 7964cae commit 89470a7
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 0 deletions.
10 changes: 10 additions & 0 deletions libnetwork/drivers/bridge/setup_device_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package bridge

import (
"context"
"errors"
"fmt"
"os"
"path/filepath"
"syscall"

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

func setupMTU(config *networkConfiguration, i *bridgeInterface) error {
if err := i.nlh.LinkSetMTU(i.Link, config.Mtu); err != nil {
// Before Linux v4.17, bridges couldn't be configured "manually" with an MTU greater than 1500, although it
// could be autoconfigured with such a value when interfaces were added to the bridge. In that case, the
// bridge MTU would be set automatically by the kernel to the lowest MTU of all interfaces attached. To keep
// compatibility with older kernels, we need to discard -EINVAL.
// TODO(aker): remove this once we drop support for CentOS/RHEL 7.
if config.Mtu > 1500 && config.Mtu <= 0xFFFF && errors.Is(err, syscall.EINVAL) {
return nil
}
log.G(context.TODO()).WithError(err).Errorf("Failed to set bridge MTU %s via netlink", config.BridgeName)
return err
}
Expand Down
34 changes: 34 additions & 0 deletions libnetwork/drivers/bridge/setup_device_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package bridge
import (
"bytes"
"net"
"syscall"
"testing"

"github.com/docker/docker/internal/testutils/netnsutils"
"github.com/docker/docker/libnetwork/netutils"
"github.com/vishvananda/netlink"
"gotest.tools/v3/assert"
)

func TestSetupNewBridge(t *testing.T) {
Expand Down Expand Up @@ -92,3 +94,35 @@ func TestGenerateRandomMAC(t *testing.T) {
t.Fatalf("Generated twice the same MAC address %v", mac1)
}
}

func TestMTUBiggerThan1500(t *testing.T) {
defer netnsutils.SetupTestOSContext(t)()

nh, err := netlink.NewHandle()
if err != nil {
t.Fatal(err)
}
defer nh.Close()

config := &networkConfiguration{BridgeName: DefaultBridgeName, Mtu: 9000}
br := &bridgeInterface{nlh: nh}

assert.NilError(t, setupDevice(config, br))
assert.NilError(t, setupMTU(config, br))
}

func TestMTUBiggerThan64K(t *testing.T) {
defer netnsutils.SetupTestOSContext(t)()

nh, err := netlink.NewHandle()
if err != nil {
t.Fatal(err)
}
defer nh.Close()

config := &networkConfiguration{BridgeName: DefaultBridgeName, Mtu: 65536}
br := &bridgeInterface{nlh: nh}

assert.NilError(t, setupDevice(config, br))
assert.ErrorIs(t, setupMTU(config, br), syscall.EINVAL)
}

0 comments on commit 89470a7

Please sign in to comment.