|
@@ -1524,16 +1524,43 @@ func (n *Network) ipamAllocate() error {
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
-func (n *Network) requestPoolHelper(ipam ipamapi.Ipam, addressSpace, preferredPool, subPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) {
|
|
|
+func (n *Network) requestPoolHelper(ipam ipamapi.Ipam, addressSpace, requestedPool, requestedSubPool string, options map[string]string, v6 bool) (poolID string, pool *net.IPNet, meta map[string]string, err error) {
|
|
|
+ var tmpPoolLeases []string
|
|
|
+ defer func() {
|
|
|
+ // Prevent repeated lock/unlock in the loop.
|
|
|
+ nwName := n.Name()
|
|
|
+ // Release all pools we held on to.
|
|
|
+ for _, pID := range tmpPoolLeases {
|
|
|
+ if err := ipam.ReleasePool(pID); err != nil {
|
|
|
+ log.G(context.TODO()).Warnf("Failed to release overlapping pool %s while returning from pool request helper for network %s", pool, nwName)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }()
|
|
|
+
|
|
|
for {
|
|
|
- poolID, pool, meta, err := ipam.RequestPool(addressSpace, preferredPool, subPool, options, v6)
|
|
|
+ poolID, pool, meta, err = ipam.RequestPool(addressSpace, requestedPool, requestedSubPool, options, v6)
|
|
|
if err != nil {
|
|
|
return "", nil, nil, err
|
|
|
}
|
|
|
|
|
|
- // If the network belongs to global scope or the pool was
|
|
|
- // explicitly chosen or it is invalid, do not perform the overlap check.
|
|
|
- if n.Scope() == scope.Global || preferredPool != "" || !types.IsIPNetValid(pool) {
|
|
|
+ // If the network pool was explicitly chosen, the network belongs to
|
|
|
+ // global scope, or it is invalid ("0.0.0.0/0"), then we don't perform
|
|
|
+ // check for overlaps.
|
|
|
+ //
|
|
|
+ // FIXME(thaJeztah): why are we ignoring invalid pools here?
|
|
|
+ //
|
|
|
+ // The "invalid" conditions was added in [libnetwork#1095][1], which
|
|
|
+ // moved code to reduce os-specific dependencies in the ipam package,
|
|
|
+ // but also introduced a types.IsIPNetValid() function, which considers
|
|
|
+ // "0.0.0.0/0" invalid, and added it to the conditions below.
|
|
|
+ //
|
|
|
+ // Unfortunately review does not mention this change, so there's no
|
|
|
+ // context why. Possibly this was done to prevent errors further down
|
|
|
+ // the line (when checking for overlaps), but returning an error here
|
|
|
+ // instead would likely have avoided that as well, so we can only guess.
|
|
|
+ //
|
|
|
+ // [1]: https://github.com/moby/libnetwork/commit/5ca79d6b87873264516323a7b76f0af7d0298492#diff-bdcd879439d041827d334846f9aba01de6e3683ed8fdd01e63917dae6df23846
|
|
|
+ if requestedPool != "" || n.Scope() == scope.Global || pool.String() == "0.0.0.0/0" {
|
|
|
return poolID, pool, meta, nil
|
|
|
}
|
|
|
|
|
@@ -1542,26 +1569,12 @@ func (n *Network) requestPoolHelper(ipam ipamapi.Ipam, addressSpace, preferredPo
|
|
|
return poolID, pool, meta, nil
|
|
|
}
|
|
|
|
|
|
- // Pool obtained in this iteration is
|
|
|
- // overlapping. Hold onto the pool and don't release
|
|
|
- // it yet, because we don't want ipam to give us back
|
|
|
- // the same pool over again. But make sure we still do
|
|
|
- // a deferred release when we have either obtained a
|
|
|
- // non-overlapping pool or ran out of pre-defined
|
|
|
- // pools.
|
|
|
- defer func() {
|
|
|
- if err := ipam.ReleasePool(poolID); err != nil {
|
|
|
- log.G(context.TODO()).Warnf("Failed to release overlapping pool %s while returning from pool request helper for network %s", pool, n.Name())
|
|
|
- }
|
|
|
- }()
|
|
|
-
|
|
|
- // If this is a preferred pool request and the network
|
|
|
- // is local scope and there is an overlap, we fail the
|
|
|
- // network creation right here. The pool will be
|
|
|
- // released in the defer.
|
|
|
- if preferredPool != "" {
|
|
|
- return "", nil, nil, fmt.Errorf("requested subnet %s overlaps in the host", preferredPool)
|
|
|
- }
|
|
|
+ // Pool obtained in this iteration is overlapping. Hold onto the pool
|
|
|
+ // and don't release it yet, because we don't want IPAM to give us back
|
|
|
+ // the same pool over again. But make sure we still do a deferred release
|
|
|
+ // when we have either obtained a non-overlapping pool or ran out of
|
|
|
+ // pre-defined pools.
|
|
|
+ tmpPoolLeases = append(tmpPoolLeases, poolID)
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1794,56 +1807,54 @@ func (n *Network) Scope() string {
|
|
|
return n.scope
|
|
|
}
|
|
|
|
|
|
-func (n *Network) IpamConfig() (string, map[string]string, []*IpamConf, []*IpamConf) {
|
|
|
+func (n *Network) IpamConfig() (ipamType string, ipamOptions map[string]string, ipamV4Config []*IpamConf, ipamV6Config []*IpamConf) {
|
|
|
n.mu.Lock()
|
|
|
defer n.mu.Unlock()
|
|
|
|
|
|
- v4L := make([]*IpamConf, len(n.ipamV4Config))
|
|
|
- v6L := make([]*IpamConf, len(n.ipamV6Config))
|
|
|
-
|
|
|
+ ipamV4Config = make([]*IpamConf, len(n.ipamV4Config))
|
|
|
for i, c := range n.ipamV4Config {
|
|
|
cc := &IpamConf{}
|
|
|
if err := c.CopyTo(cc); err != nil {
|
|
|
log.G(context.TODO()).WithError(err).Error("Error copying ipam ipv4 config")
|
|
|
}
|
|
|
- v4L[i] = cc
|
|
|
+ ipamV4Config[i] = cc
|
|
|
}
|
|
|
|
|
|
+ ipamV6Config = make([]*IpamConf, len(n.ipamV6Config))
|
|
|
for i, c := range n.ipamV6Config {
|
|
|
cc := &IpamConf{}
|
|
|
if err := c.CopyTo(cc); err != nil {
|
|
|
log.G(context.TODO()).WithError(err).Debug("Error copying ipam ipv6 config")
|
|
|
}
|
|
|
- v6L[i] = cc
|
|
|
+ ipamV6Config[i] = cc
|
|
|
}
|
|
|
|
|
|
- return n.ipamType, n.ipamOptions, v4L, v6L
|
|
|
+ return n.ipamType, n.ipamOptions, ipamV4Config, ipamV6Config
|
|
|
}
|
|
|
|
|
|
-func (n *Network) IpamInfo() ([]*IpamInfo, []*IpamInfo) {
|
|
|
+func (n *Network) IpamInfo() (ipamV4Info []*IpamInfo, ipamV6Info []*IpamInfo) {
|
|
|
n.mu.Lock()
|
|
|
defer n.mu.Unlock()
|
|
|
|
|
|
- v4Info := make([]*IpamInfo, len(n.ipamV4Info))
|
|
|
- v6Info := make([]*IpamInfo, len(n.ipamV6Info))
|
|
|
-
|
|
|
+ ipamV4Info = make([]*IpamInfo, len(n.ipamV4Info))
|
|
|
for i, info := range n.ipamV4Info {
|
|
|
ic := &IpamInfo{}
|
|
|
if err := info.CopyTo(ic); err != nil {
|
|
|
- log.G(context.TODO()).WithError(err).Error("Error copying ipv4 ipam config")
|
|
|
+ log.G(context.TODO()).WithError(err).Error("Error copying IPv4 IPAM config")
|
|
|
}
|
|
|
- v4Info[i] = ic
|
|
|
+ ipamV4Info[i] = ic
|
|
|
}
|
|
|
|
|
|
+ ipamV6Info = make([]*IpamInfo, len(n.ipamV6Info))
|
|
|
for i, info := range n.ipamV6Info {
|
|
|
ic := &IpamInfo{}
|
|
|
if err := info.CopyTo(ic); err != nil {
|
|
|
- log.G(context.TODO()).WithError(err).Error("Error copying ipv6 ipam config")
|
|
|
+ log.G(context.TODO()).WithError(err).Error("Error copying IPv6 IPAM config")
|
|
|
}
|
|
|
- v6Info[i] = ic
|
|
|
+ ipamV6Info[i] = ic
|
|
|
}
|
|
|
|
|
|
- return v4Info, v6Info
|
|
|
+ return ipamV4Info, ipamV6Info
|
|
|
}
|
|
|
|
|
|
func (n *Network) Internal() bool {
|