libnetwork: loosen container IPAM validation

Permit container network attachments to set any static IP address within
the network's IPAM master pool, including when a subpool is configured.
Users have come to depend on being able to statically assign container
IP addresses which are guaranteed not to collide with automatically-
assigned container addresses.

Signed-off-by: Cory Snider <csnider@mirantis.com>
(cherry picked from commit 058b30023f)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Cory Snider 2024-01-19 20:18:15 -05:00 committed by Sebastiaan van Stijn
parent 615dfdf672
commit 13964248f1
No known key found for this signature in database
GPG key ID: 76698F39D527CE8C
3 changed files with 45 additions and 5 deletions

View file

@ -289,3 +289,40 @@ func TestMacAddressIsAppliedToMainNetworkWithShortID(t *testing.T) {
c := container.Inspect(ctx, t, apiClient, cid)
assert.Equal(t, c.NetworkSettings.Networks["testnet"].MacAddress, "02:42:08:26:a9:55")
}
func TestStaticIPOutsideSubpool(t *testing.T) {
skip.If(t, testEnv.IsRemoteDaemon)
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
ctx := testutil.StartSpan(baseContext, t)
d := daemon.New(t)
d.StartWithBusybox(ctx, t)
defer d.Stop(t)
apiClient, err := client.NewClientWithOpts(client.FromEnv, client.WithVersion("1.43"))
assert.NilError(t, err)
const netname = "subnet-range"
n := net.CreateNoError(ctx, t, apiClient, netname, net.WithIPAMRange("10.42.0.0/16", "10.42.128.0/24", "10.42.0.1"))
defer net.RemoveNoError(ctx, t, apiClient, n)
cID := container.Run(ctx, t, apiClient,
container.WithImage("busybox:latest"),
container.WithCmd("sh", "-c", `ip -4 -oneline addr show eth0`),
container.WithNetworkMode(netname),
container.WithIPv4(netname, "10.42.1.3"),
)
poll.WaitOn(t, container.IsStopped(ctx, apiClient, cID), poll.WithDelay(100*time.Millisecond))
out, err := apiClient.ContainerLogs(ctx, cID, containertypes.LogsOptions{ShowStdout: true})
assert.NilError(t, err)
defer out.Close()
var b bytes.Buffer
_, err = io.Copy(&b, out)
assert.NilError(t, err)
assert.Check(t, is.Contains(b.String(), "inet 10.42.1.3/16"))
}

View file

@ -73,6 +73,11 @@ func WithOption(key, value string) func(*types.NetworkCreate) {
// WithIPAM adds an IPAM with the specified Subnet and Gateway to the network
func WithIPAM(subnet, gateway string) func(*types.NetworkCreate) {
return WithIPAMRange(subnet, "", gateway)
}
// WithIPAM adds an IPAM with the specified Subnet, IPRange and Gateway to the network
func WithIPAMRange(subnet, iprange, gateway string) func(*types.NetworkCreate) {
return func(n *types.NetworkCreate) {
if n.IPAM == nil {
n.IPAM = &network.IPAM{}
@ -80,6 +85,7 @@ func WithIPAM(subnet, gateway string) func(*types.NetworkCreate) {
n.IPAM.Config = append(n.IPAM.Config, network.IPAMConfig{
Subnet: subnet,
IPRange: iprange,
Gateway: gateway,
AuxAddress: map[string]string{},
})

View file

@ -83,7 +83,7 @@ type IpamConf struct {
// PreferredPool is the master address pool for containers and network interfaces.
PreferredPool string
// SubPool is a subset of the master pool. If specified,
// this becomes the container pool.
// this becomes the container pool for automatic address allocations.
SubPool string
// Gateway is the preferred Network Gateway address (optional).
Gateway string
@ -100,7 +100,7 @@ func (c *IpamConf) Validate() error {
return nil
}
// Contains checks whether the ipamSubnet contains [addr].
// Contains checks whether the ipam master address pool contains [addr].
func (c *IpamConf) Contains(addr net.IP) bool {
if c == nil {
return false
@ -110,9 +110,6 @@ func (c *IpamConf) Contains(addr net.IP) bool {
}
_, allowedRange, _ := net.ParseCIDR(c.PreferredPool)
if c.SubPool != "" {
_, allowedRange, _ = net.ParseCIDR(c.SubPool)
}
return allowedRange.Contains(addr)
}