diff --git a/libnetwork/endpoint.go b/libnetwork/endpoint.go index d5f38c51a2..b0eed2b626 100644 --- a/libnetwork/endpoint.go +++ b/libnetwork/endpoint.go @@ -61,6 +61,7 @@ type endpoint struct { generic map[string]interface{} joinLeaveDone chan struct{} prefAddress net.IP + prefAddressV6 net.IP ipamOptions map[string]string dbIndex uint64 dbExists bool @@ -688,9 +689,10 @@ func EndpointOptionGeneric(generic map[string]interface{}) EndpointOption { } // CreateOptionIpam function returns an option setter for the ipam configuration for this endpoint -func CreateOptionIpam(prefAddress net.IP, ipamOptions map[string]string) EndpointOption { +func CreateOptionIpam(ipV4, ipV6 net.IP, ipamOptions map[string]string) EndpointOption { return func(ep *endpoint) { - ep.prefAddress = prefAddress + ep.prefAddress = ipV4 + ep.prefAddressV6 = ipV6 ep.ipamOptions = ipamOptions } } @@ -775,6 +777,8 @@ func (ep *endpoint) assignAddressVersion(ipVer int, ipam ipamapi.Ipam) error { var ( poolID *string address **net.IPNet + prefAdd net.IP + progAdd net.IP ) n := ep.getNetwork() @@ -782,9 +786,11 @@ func (ep *endpoint) assignAddressVersion(ipVer int, ipam ipamapi.Ipam) error { case 4: poolID = &ep.iface.v4PoolID address = &ep.iface.addr + prefAdd = ep.prefAddress case 6: poolID = &ep.iface.v6PoolID address = &ep.iface.addrv6 + prefAdd = ep.prefAddressV6 default: return types.InternalErrorf("incorrect ip version number passed: %d", ipVer) } @@ -796,12 +802,19 @@ func (ep *endpoint) assignAddressVersion(ipVer int, ipam ipamapi.Ipam) error { return nil } + // The address to program may be chosen by the user or by the network driver in one specific + // case to support backward compatibility with `docker daemon --fixed-cidrv6` use case + if prefAdd != nil { + progAdd = prefAdd + } else if *address != nil { + progAdd = (*address).IP + } + for _, d := range ipInfo { - var prefIP net.IP - if *address != nil { - prefIP = (*address).IP + if progAdd != nil && !d.Pool.Contains(progAdd) { + continue } - addr, _, err := ipam.RequestAddress(d.PoolID, prefIP, ep.ipamOptions) + addr, _, err := ipam.RequestAddress(d.PoolID, progAdd, ep.ipamOptions) if err == nil { ep.Lock() *address = addr @@ -809,10 +822,13 @@ func (ep *endpoint) assignAddressVersion(ipVer int, ipam ipamapi.Ipam) error { ep.Unlock() return nil } - if err != ipamapi.ErrNoAvailableIPs { + if err != ipamapi.ErrNoAvailableIPs || progAdd != nil { return err } } + if progAdd != nil { + return types.BadRequestErrorf("Invalid preferred address %s: It does not belong to any of this network's subnets") + } return fmt.Errorf("no available IPv%d addresses on this network's address pools: %s (%s)", ipVer, n.Name(), n.ID()) }