func releasePools(ipam ipamapi.Ipam, icList []*api.IPAMConfig, pools map[string]string) { for _, ic := range icList { if err := ipam.ReleaseAddress(pools[ic.Subnet], net.ParseIP(ic.Gateway)); err != nil { log.G(context.TODO()).Errorf("Failed to release address %s: %v", ic.Subnet, err) } } for k, p := range pools { if err := ipam.ReleasePool(p); err != nil { log.G(context.TODO()).Errorf("Failed to release pool %s: %v", k, err) } } }
func (n *network) ipamReleaseVersion(ipVer int, ipam ipamapi.Ipam) { var infoList *[]*IpamInfo switch ipVer { case 4: infoList = &n.ipamV4Info case 6: infoList = &n.ipamV6Info default: log.Warnf("incorrect ip version passed to ipam release: %d", ipVer) return } if len(*infoList) == 0 { return } log.Debugf("releasing IPv%d pools from network %s (%s)", ipVer, n.Name(), n.ID()) for _, d := range *infoList { if d.Gateway != nil { if err := ipam.ReleaseAddress(d.PoolID, d.Gateway.IP); err != nil { log.Warnf("Failed to release gateway ip address %s on delete of network %s (%s): %v", d.Gateway.IP, n.Name(), n.ID(), err) } } if d.IPAMData.AuxAddresses != nil { for k, nw := range d.IPAMData.AuxAddresses { if d.Pool.Contains(nw.IP) { if err := ipam.ReleaseAddress(d.PoolID, nw.IP); err != nil && err != ipamapi.ErrIPOutOfRange { log.Warnf("Failed to release secondary ip address %s (%v) on delete of network %s (%s): %v", k, nw.IP, n.Name(), n.ID(), err) } } } } if err := ipam.ReleasePool(d.PoolID); err != nil { log.Warnf("Failed to release address pool %s on delete of network %s (%s): %v", d.PoolID, n.Name(), n.ID(), err) } } *infoList = nil }
func (n *network) requestPoolHelper(ipam ipamapi.Ipam, addressSpace, preferredPool, subPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) { for { poolID, pool, meta, err := ipam.RequestPool(addressSpace, preferredPool, subPool, options, v6) if err != nil { return "", nil, nil, err } // If the network belongs to global scope or the pool was // explicitely chosen or it is invalid, do not perform the overlap check. if n.Scope() == datastore.GlobalScope || preferredPool != "" || !types.IsIPNetValid(pool) { return poolID, pool, meta, nil } // Check for overlap and if none found, we have found the right pool. if _, err := netutils.FindAvailableNetwork([]*net.IPNet{pool}); err == nil { 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.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 a 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) } } }
func (n *network) ipamAllocateVersion(ipVer int, ipam ipamapi.Ipam) error { var ( cfgList *[]*IpamConf infoList *[]*IpamInfo err error ) switch ipVer { case 4: cfgList = &n.ipamV4Config infoList = &n.ipamV4Info case 6: cfgList = &n.ipamV6Config infoList = &n.ipamV6Info default: return types.InternalErrorf("incorrect ip version passed to ipam allocate: %d", ipVer) } if len(*cfgList) == 0 { if ipVer == 6 { return nil } *cfgList = []*IpamConf{{}} } *infoList = make([]*IpamInfo, len(*cfgList)) log.Debugf("Allocating IPv%d pools for network %s (%s)", ipVer, n.Name(), n.ID()) for i, cfg := range *cfgList { if err = cfg.Validate(); err != nil { return err } d := &IpamInfo{} (*infoList)[i] = d d.AddressSpace = n.addrSpace d.PoolID, d.Pool, d.Meta, err = n.requestPoolHelper(ipam, n.addrSpace, cfg.PreferredPool, cfg.SubPool, n.ipamOptions, ipVer == 6) if err != nil { return err } defer func() { if err != nil { if err := ipam.ReleasePool(d.PoolID); err != nil { log.Warnf("Failed to release address pool %s after failure to create network %s (%s)", d.PoolID, n.Name(), n.ID()) } } }() if gws, ok := d.Meta[netlabel.Gateway]; ok { if d.Gateway, err = types.ParseCIDR(gws); err != nil { return types.BadRequestErrorf("failed to parse gateway address (%v) returned by ipam driver: %v", gws, err) } } // If user requested a specific gateway, libnetwork will allocate it // irrespective of whether ipam driver returned a gateway already. // If none of the above is true, libnetwork will allocate one. if cfg.Gateway != "" || d.Gateway == nil { var gatewayOpts = map[string]string{ ipamapi.RequestAddressType: netlabel.Gateway, } if d.Gateway, _, err = ipam.RequestAddress(d.PoolID, net.ParseIP(cfg.Gateway), gatewayOpts); err != nil { return types.InternalErrorf("failed to allocate gateway (%v): %v", cfg.Gateway, err) } } // Auxiliary addresses must be part of the master address pool // If they fall into the container addressable pool, libnetwork will reserve them if cfg.AuxAddresses != nil { var ip net.IP d.IPAMData.AuxAddresses = make(map[string]*net.IPNet, len(cfg.AuxAddresses)) for k, v := range cfg.AuxAddresses { if ip = net.ParseIP(v); ip == nil { return types.BadRequestErrorf("non parsable secondary ip address (%s:%s) passed for network %s", k, v, n.Name()) } if !d.Pool.Contains(ip) { return types.ForbiddenErrorf("auxilairy address: (%s:%s) must belong to the master pool: %s", k, v, d.Pool) } // Attempt reservation in the container addressable pool, silent the error if address does not belong to that pool if d.IPAMData.AuxAddresses[k], _, err = ipam.RequestAddress(d.PoolID, ip, nil); err != nil && err != ipamapi.ErrIPOutOfRange { return types.InternalErrorf("failed to allocate secondary ip address (%s:%s): %v", k, v, err) } } } } return nil }