func (r *DrvRegistry) registerIpamDriver(name string, driver ipamapi.Ipam, caps *ipamapi.Capability) error { if strings.TrimSpace(name) == "" { return fmt.Errorf("ipam driver name string cannot be empty") } r.Lock() _, ok := r.ipamDrivers[name] r.Unlock() if ok { return types.ForbiddenErrorf("ipam driver %q already registered", name) } locAS, glbAS, err := driver.GetDefaultAddressSpaces() if err != nil { return types.InternalErrorf("ipam driver %q failed to return default address spaces: %v", name, err) } if r.ifn != nil { if err := r.ifn(name, driver, caps); err != nil { return err } } r.Lock() r.ipamDrivers[name] = &ipamData{driver: driver, defaultLocalAddressSpace: locAS, defaultGlobalAddressSpace: glbAS, capability: caps} r.Unlock() return nil }
func (ep *endpoint) assignAddress() error { var ( ipam ipamapi.Ipam err error ) n := ep.getNetwork() if n.Type() == "host" || n.Type() == "null" || n.Type() == "bridge" { return nil } ipam, err = n.getController().getIpamDriver(n.ipamType) if err != nil { return err } for _, d := range n.getIPInfo() { var addr *net.IPNet addr, _, err = ipam.RequestAddress(d.PoolID, nil, nil) if err == nil { ep.Lock() ep.iface.addr = addr ep.iface.poolID = d.PoolID ep.Unlock() return nil } if err != ipamapi.ErrNoAvailableIPs { return err } } return fmt.Errorf("no available ip addresses on this network address pools: %s (%s)", n.Name(), n.ID()) }
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() switch ipVer { 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) } ipInfo := n.getIPInfo(ipVer) // ipv6 address is not mandatory if len(ipInfo) == 0 && ipVer == 6 { 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 { if progAdd != nil && !d.Pool.Contains(progAdd) { continue } addr, _, err := ipam.RequestAddress(d.PoolID, progAdd, ep.ipamOptions) if err == nil { ep.Lock() *address = addr *poolID = d.PoolID ep.Unlock() return nil } if err != ipamapi.ErrNoAvailableIPs || progAdd != nil { return err } } if progAdd != nil { return types.BadRequestErrorf("Invalid address %s: It does not belong to any of this network's subnets", prefAdd) } return fmt.Errorf("no available IPv%d addresses on this network's address pools: %s (%s)", ipVer, n.Name(), n.ID()) }
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 (ep *endpoint) assignAddressVersion(ipVer int, ipam ipamapi.Ipam) error { var ( poolID *string address **net.IPNet ) n := ep.getNetwork() switch ipVer { case 4: poolID = &ep.iface.v4PoolID address = &ep.iface.addr case 6: poolID = &ep.iface.v6PoolID address = &ep.iface.addrv6 default: return types.InternalErrorf("incorrect ip version number passed: %d", ipVer) } ipInfo := n.getIPInfo(ipVer) // ipv6 address is not mandatory if len(ipInfo) == 0 && ipVer == 6 { return nil } for _, d := range ipInfo { var prefIP net.IP if *address != nil { prefIP = (*address).IP } addr, _, err := ipam.RequestAddress(d.PoolID, prefIP, nil) if err == nil { ep.Lock() *address = addr *poolID = d.PoolID ep.Unlock() return nil } if err != ipamapi.ErrNoAvailableIPs { return err } } return fmt.Errorf("no available IPv%d addresses on this network's address pools: %s (%s)", ipVer, n.Name(), n.ID()) }
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 (c *controller) RegisterIpamDriver(name string, driver ipamapi.Ipam) error { if !config.IsValidName(name) { return ErrInvalidName(name) } c.Lock() _, ok := c.ipamDrivers[name] c.Unlock() if ok { return driverapi.ErrActiveRegistration(name) } locAS, glbAS, err := driver.GetDefaultAddressSpaces() if err != nil { return fmt.Errorf("ipam driver %s failed to return default address spaces: %v", name, err) } c.Lock() c.ipamDrivers[name] = &ipamData{driver: driver, defaultLocalAddressSpace: locAS, defaultGlobalAddressSpace: glbAS} c.Unlock() log.Debugf("Registering ipam provider: %s", name) return nil }
func (c *controller) registerIpamDriver(name string, driver ipamapi.Ipam, caps *ipamapi.Capability) error { if !config.IsValidName(name) { return ErrInvalidName(name) } c.Lock() _, ok := c.ipamDrivers[name] c.Unlock() if ok { return types.ForbiddenErrorf("ipam driver %q already registered", name) } locAS, glbAS, err := driver.GetDefaultAddressSpaces() if err != nil { return types.InternalErrorf("ipam driver %q failed to return default address spaces: %v", name, err) } c.Lock() c.ipamDrivers[name] = &ipamData{driver: driver, defaultLocalAddressSpace: locAS, defaultGlobalAddressSpace: glbAS, capability: caps} c.Unlock() log.Debugf("Registering ipam driver: %q", name) return nil }
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) 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 }