Merge pull request #50114 from danegsta/50107-defaultpoolsize

Proposal: Allow specifying the subnet size for networks allocated from default pools
This commit is contained in:
Albin Kerouanton
2025-10-23 08:53:38 +02:00
committed by GitHub
10 changed files with 381 additions and 55 deletions

View File

@@ -70,8 +70,8 @@ func TestDaemonDefaultBridgeIPAM_Docker0(t *testing.T) {
"--fixed-cidr-v6", "fdd1:8161:2d2c::/64",
},
expIPAMConfig: []network.IPAMConfig{
{Subnet: netip.MustParsePrefix("192.168.176.0/24"), IPRange: netip.MustParsePrefix("192.168.176.0/24")},
{Subnet: netip.MustParsePrefix("fdd1:8161:2d2c::/64"), IPRange: netip.MustParsePrefix("fdd1:8161:2d2c::/64")},
{Subnet: netip.MustParsePrefix("192.168.176.0/24"), IPRange: netip.MustParsePrefix("192.168.176.0/24"), Gateway: netip.MustParseAddr("192.168.176.1")},
{Subnet: netip.MustParsePrefix("fdd1:8161:2d2c::/64"), IPRange: netip.MustParsePrefix("fdd1:8161:2d2c::/64"), Gateway: netip.MustParseAddr("fdd1:8161:2d2c::1")},
},
},
{
@@ -123,7 +123,7 @@ func TestDaemonDefaultBridgeIPAM_Docker0(t *testing.T) {
"--fixed-cidr-v6", "fe80::/64",
},
expIPAMConfig: []network.IPAMConfig{
{Subnet: netip.MustParsePrefix("192.168.176.0/24"), IPRange: netip.MustParsePrefix("192.168.176.0/24")},
{Subnet: netip.MustParsePrefix("192.168.176.0/24"), IPRange: netip.MustParsePrefix("192.168.176.0/24"), Gateway: netip.MustParseAddr("192.168.176.1")},
{Subnet: netip.MustParsePrefix("fe80::/64"), IPRange: netip.MustParsePrefix("fe80::/64"), Gateway: llGwPlaceholder},
},
},
@@ -173,15 +173,8 @@ func TestDaemonDefaultBridgeIPAM_Docker0(t *testing.T) {
// The bridge's address/subnet should be ignored, this is a change
// of fixed-cidr.
expIPAMConfig: []network.IPAMConfig{
{Subnet: netip.MustParsePrefix("192.168.177.0/24"), IPRange: netip.MustParsePrefix("192.168.177.0/24")},
{Subnet: netip.MustParsePrefix("fdd1:8161:2d2c:1::/64"), IPRange: netip.MustParsePrefix("fdd1:8161:2d2c:1::/64")},
// No Gateway is configured, because the address could not be learnt from the
// bridge. An address will have been allocated but, because there's config (the
// fixed-cidr), inspect shows just the config. (Surprisingly, when there's no
// config at all, the inspect output still says its showing config but actually
// shows the running state.) When the daemon is restarted, after a gateway
// address has been assigned to the bridge, that address will become config - so
// a Gateway address will show up in the inspect output.
{Subnet: netip.MustParsePrefix("192.168.177.0/24"), IPRange: netip.MustParsePrefix("192.168.177.0/24"), Gateway: netip.MustParseAddr("192.168.177.1")},
{Subnet: netip.MustParsePrefix("fdd1:8161:2d2c:1::/64"), IPRange: netip.MustParsePrefix("fdd1:8161:2d2c:1::/64"), Gateway: netip.MustParseAddr("fdd1:8161:2d2c:1::1")},
},
},
{
@@ -225,8 +218,8 @@ func TestDaemonDefaultBridgeIPAM_UserBr(t *testing.T) {
"--fixed-cidr-v6", "fdd1:8161:2d2c::/64",
},
expIPAMConfig: []network.IPAMConfig{
{Subnet: netip.MustParsePrefix("192.168.176.0/24"), IPRange: netip.MustParsePrefix("192.168.176.0/24")},
{Subnet: netip.MustParsePrefix("fdd1:8161:2d2c::/64"), IPRange: netip.MustParsePrefix("fdd1:8161:2d2c::/64")},
{Subnet: netip.MustParsePrefix("192.168.176.0/24"), IPRange: netip.MustParsePrefix("192.168.176.0/24"), Gateway: netip.MustParseAddr("192.168.176.1")},
{Subnet: netip.MustParsePrefix("fdd1:8161:2d2c::/64"), IPRange: netip.MustParsePrefix("fdd1:8161:2d2c::/64"), Gateway: netip.MustParseAddr("fdd1:8161:2d2c::1")},
},
},
{
@@ -428,7 +421,7 @@ func testDefaultBridgeIPAM(ctx context.Context, t *testing.T, tc defaultBridgeIP
expIPAMConfig[i].Gateway = llAddr
}
}
assert.Check(t, is.DeepEqual(res.Network.IPAM.Config, expIPAMConfig, cmpopts.EquateComparable(netip.Addr{}, netip.Prefix{})))
assert.Check(t, is.DeepEqual(res.Network.IPAM.Config, expIPAMConfig, cmpopts.EquateComparable(netip.Addr{}, netip.Prefix{})), "unexpected IPAM config '%s'", tc.name)
})
})
}

View File

@@ -33,6 +33,21 @@ func CreateNoError(ctx context.Context, t *testing.T, apiClient client.APIClient
return name
}
// Inspect inspects a network with the specified options
func Inspect(ctx context.Context, apiClient client.APIClient, name string, options client.NetworkInspectOptions) (client.NetworkInspectResult, error) {
return apiClient.NetworkInspect(ctx, name, options)
}
// InspectNoError inspects a network with the specified options and verifies there were no errors
func InspectNoError(ctx context.Context, t *testing.T, apiClient client.APIClient, name string, options client.NetworkInspectOptions) client.NetworkInspectResult {
t.Helper()
c, err := apiClient.NetworkInspect(ctx, name, options)
assert.NilError(t, err)
return c
}
func RemoveNoError(ctx context.Context, t *testing.T, apiClient client.APIClient, name string) {
t.Helper()

View File

@@ -1287,3 +1287,95 @@ func TestJoinError(t *testing.T) {
res = ctr.ExecT(ctx, t, c, cid, []string{"ip", "link", "show", "eth1"})
assert.Check(t, is.Equal(res.ExitCode, 0), "container should have an eth1")
}
func TestPreferredSubnetRestore(t *testing.T) {
skip.If(t, testEnv.IsRootless(), "fails before and after restart")
ctx := setupTest(t)
d := daemon.New(t)
d.StartWithBusybox(ctx, t)
defer d.Stop(t)
c := d.NewClientT(t)
const v4netName = "testnetv4restore"
network.CreateNoError(ctx, t, c, v4netName,
network.WithIPv4(true),
network.WithIPAMConfig(networktypes.IPAMConfig{
Subnet: netip.MustParsePrefix("0.0.0.0/24"),
}),
)
defer func() { network.RemoveNoError(ctx, t, c, v4netName) }()
const v6netName = "testnetv6restore"
network.CreateNoError(ctx, t, c, v6netName,
network.WithIPv4(false),
network.WithIPv6(),
network.WithIPAMConfig(networktypes.IPAMConfig{
Subnet: netip.MustParsePrefix("::/120"),
}),
)
defer func() { network.RemoveNoError(ctx, t, c, v6netName) }()
const dualStackNetName = "testnetdualrestore"
network.CreateNoError(ctx, t, c, dualStackNetName,
network.WithIPv4(true),
network.WithIPv6(),
network.WithIPAMConfig(networktypes.IPAMConfig{
Subnet: netip.MustParsePrefix("0.0.0.0/24"),
}, networktypes.IPAMConfig{
Subnet: netip.MustParsePrefix("::/120"),
}),
)
defer func() { network.RemoveNoError(ctx, t, c, dualStackNetName) }()
inspOpts := client.NetworkInspectOptions{}
v4Insp := network.InspectNoError(ctx, t, c, v4netName, inspOpts)
assert.Check(t, is.Len(v4Insp.Network.IPAM.Config, 1))
v4allocCidr := v4Insp.Network.IPAM.Config[0].Subnet
assert.Check(t, is.Equal(v4allocCidr.Addr().IsUnspecified(), false), "expected specific subnet")
v6Insp := network.InspectNoError(ctx, t, c, v6netName, inspOpts)
assert.Check(t, is.Len(v6Insp.Network.IPAM.Config, 1))
v6allocCidr := v6Insp.Network.IPAM.Config[0].Subnet
assert.Check(t, is.Equal(v6allocCidr.Addr().IsUnspecified(), false), "expected specific subnet")
dualStackInsp := network.InspectNoError(ctx, t, c, dualStackNetName, inspOpts)
assert.Check(t, is.Len(dualStackInsp.Network.IPAM.Config, 2))
var dualv4, dualv6 netip.Prefix
if dualStackInsp.Network.IPAM.Config[0].Subnet.Addr().Is4() {
dualv4 = dualStackInsp.Network.IPAM.Config[0].Subnet
dualv6 = dualStackInsp.Network.IPAM.Config[1].Subnet
} else {
dualv4 = dualStackInsp.Network.IPAM.Config[1].Subnet
dualv6 = dualStackInsp.Network.IPAM.Config[0].Subnet
}
assert.Check(t, is.Equal(dualv4.Addr().IsUnspecified(), false), "expected specific v4 subnet")
assert.Check(t, is.Equal(dualv6.Addr().IsUnspecified(), false), "expected specific v6 subnet")
d.Restart(t)
v4Insp = network.InspectNoError(ctx, t, c, v4netName, inspOpts)
assert.Check(t, is.Len(v4Insp.Network.IPAM.Config, 1))
assert.Check(t, is.Equal(v4Insp.Network.IPAM.Config[0].Subnet, v4allocCidr))
v6Insp = network.InspectNoError(ctx, t, c, v6netName, inspOpts)
assert.Check(t, is.Len(v6Insp.Network.IPAM.Config, 1))
assert.Check(t, is.Equal(v6Insp.Network.IPAM.Config[0].Subnet, v6allocCidr))
dualStackInsp = network.InspectNoError(ctx, t, c, dualStackNetName, inspOpts)
assert.Check(t, is.Len(dualStackInsp.Network.IPAM.Config, 2))
var dualv4after, dualv6after netip.Prefix
if dualStackInsp.Network.IPAM.Config[0].Subnet.Addr().Is4() {
dualv4after = dualStackInsp.Network.IPAM.Config[0].Subnet
dualv6after = dualStackInsp.Network.IPAM.Config[1].Subnet
} else {
dualv4after = dualStackInsp.Network.IPAM.Config[1].Subnet
dualv6after = dualStackInsp.Network.IPAM.Config[0].Subnet
}
assert.Check(t, is.Equal(dualv4after, dualv4), "expected same v4 subnet after restart")
assert.Check(t, is.Equal(dualv6after, dualv6), "expected same v6 subnet after restart")
}