From 43f71fb58209ea342c546cc489d069097108a70f Mon Sep 17 00:00:00 2001 From: Rob Murray Date: Fri, 10 Jan 2025 10:38:23 +0000 Subject: [PATCH] Bridge - skip gateway allocation if no gateway is needed An "--internal" bridge network will never set up a default route and, with "-o com.docker.network.bridge.inhibit_ipv4", no Gateway address will be assigned to the bridge. So, implement the SkipGwAlloc interface in the bridge driver, and use it to to indicate that no Gateway address is required in this specific case. Signed-off-by: Rob Murray --- .../network/bridge/bridge_linux_test.go | 35 +++++++++++++++++++ libnetwork/drivers/bridge/bridge_linux.go | 13 +++++++ 2 files changed, 48 insertions(+) diff --git a/integration/network/bridge/bridge_linux_test.go b/integration/network/bridge/bridge_linux_test.go index 8d3ea66d66..6d59d56f0e 100644 --- a/integration/network/bridge/bridge_linux_test.go +++ b/integration/network/bridge/bridge_linux_test.go @@ -14,6 +14,7 @@ import ( ctr "github.com/docker/docker/integration/internal/container" "github.com/docker/docker/integration/internal/network" "github.com/docker/docker/internal/testutils/networking" + "github.com/docker/docker/libnetwork/drivers/bridge" "github.com/docker/docker/testutil" "github.com/docker/docker/testutil/daemon" "gotest.tools/v3/assert" @@ -315,3 +316,37 @@ func TestFilterForwardPolicy(t *testing.T) { }) } } + +// TestPointToPoint checks that a "/31" --internal network with inhibit_ipv4 +// has two addresses available for containers (no address is reserved for a +// gateway, because it won't be used). +func TestPointToPoint(t *testing.T) { + ctx := setupTest(t) + apiClient := testEnv.APIClient() + + const netName = "testp2pbridge" + network.CreateNoError(ctx, t, apiClient, netName, + network.WithIPAM("192.168.135.0/31", ""), + network.WithInternal(), + network.WithOption(bridge.InhibitIPv4, "true"), + ) + defer network.RemoveNoError(ctx, t, apiClient, netName) + + const ctrName = "ctr1" + id := ctr.Run(ctx, t, apiClient, + ctr.WithNetworkMode(netName), + ctr.WithName(ctrName), + ) + defer apiClient.ContainerRemove(ctx, id, containertypes.RemoveOptions{Force: true}) + + attachCtx, cancel := context.WithTimeout(ctx, 5*time.Second) + defer cancel() + res := ctr.RunAttach(attachCtx, t, apiClient, + ctr.WithCmd([]string{"ping", "-c1", "-W3", ctrName}...), + ctr.WithNetworkMode(netName), + ) + defer apiClient.ContainerRemove(ctx, res.ContainerID, containertypes.RemoveOptions{Force: true}) + assert.Check(t, is.Equal(res.ExitCode, 0)) + assert.Check(t, is.Equal(res.Stderr.Len(), 0)) + assert.Check(t, is.Contains(res.Stdout.String(), "1 packets transmitted, 1 packets received")) +} diff --git a/libnetwork/drivers/bridge/bridge_linux.go b/libnetwork/drivers/bridge/bridge_linux.go index 10ff4af125..4c333a3331 100644 --- a/libnetwork/drivers/bridge/bridge_linux.go +++ b/libnetwork/drivers/bridge/bridge_linux.go @@ -745,6 +745,19 @@ func (d *driver) DecodeTableEntry(tablename string, key string, value []byte) (s return "", nil } +func (d *driver) GetSkipGwAlloc(opts options.Generic) (ipv4, ipv6 bool, _ error) { + // The network doesn't exist yet, so use a dummy id that's long enough to be + // truncated to a short-id (12 characters) and used in the bridge device name. + cfg, err := parseNetworkOptions("dummyNetworkId", opts) + if err != nil { + return false, false, err + } + // cfg.InhibitIPv4 means no gateway address will be assigned to the bridge, if + // the network is also cfg.Internal, there will not be a default route to use + // the gateway address either. + return cfg.InhibitIPv4 && cfg.Internal, false, nil +} + // CreateNetwork creates a new network using the bridge driver. func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error { // Sanity checks