func (a *Allocator) getAddress(nw *net.IPNet, bitmask *bitseq.Handle, prefAddress net.IP, ipr *AddressRange) (net.IP, error) { var ( ordinal uint64 err error base *net.IPNet ) base = types.GetIPNetCopy(nw) if bitmask.Unselected() <= 0 { return nil, ipamapi.ErrNoAvailableIPs } if ipr == nil && prefAddress == nil { ordinal, err = bitmask.SetAny() } else if prefAddress != nil { hostPart, e := types.GetHostPartIP(prefAddress, base.Mask) if e != nil { return nil, fmt.Errorf("failed to allocate preferred address %s: %v", prefAddress.String(), e) } ordinal = ipToUint64(types.GetMinimalIP(hostPart)) err = bitmask.Set(ordinal) } else { base.IP = ipr.Sub.IP ordinal, err = bitmask.SetAnyInRange(ipr.Start, ipr.End) } if err != nil { return nil, ipamapi.ErrNoAvailableIPs } // Convert IP ordinal for this subnet into IP address return generateAddress(ordinal, base), nil }
func (a *Allocator) getAddress(subnet *net.IPNet, bitmask *bitseq.Handle, prefAddress net.IP, ver ipVersion) (net.IP, error) { var ( ordinal uint32 err error ) if bitmask.Unselected() <= 0 { return nil, ErrNoAvailableIPs } if prefAddress == nil { ordinal, err = bitmask.SetAny() } else { hostPart, e := types.GetHostPartIP(prefAddress, subnet.Mask) if e != nil { return nil, fmt.Errorf("failed to allocate preferred address %s: %v", prefAddress.String(), e) } ordinal = ipToUint32(types.GetMinimalIP(hostPart)) err = bitmask.Set(ordinal) } if err != nil { return nil, ErrNoAvailableIPs } // Convert IP ordinal for this subnet into IP address return generateAddress(ordinal, subnet), nil }
// ReleaseAddress releases the address from the specified pool ID func (a *Allocator) ReleaseAddress(poolID string, address net.IP) error { log.Debugf("ReleaseAddress(%s, %v)", poolID, address) k := SubnetKey{} if err := k.FromString(poolID); err != nil { return types.BadRequestErrorf("invalid pool id: %s", poolID) } if err := a.refresh(k.AddressSpace); err != nil { return err } aSpace, err := a.getAddrSpace(k.AddressSpace) if err != nil { return err } aSpace.Lock() p, ok := aSpace.subnets[k] if !ok { aSpace.Unlock() return ipamapi.ErrBadPool } if address == nil { aSpace.Unlock() return ipamapi.ErrInvalidRequest } if !p.Pool.Contains(address) { aSpace.Unlock() return ipamapi.ErrIPOutOfRange } c := p for c.Range != nil { k = c.ParentKey c = aSpace.subnets[k] } aSpace.Unlock() mask := p.Pool.Mask if p.Range != nil { mask = p.Range.Sub.Mask } h, err := types.GetHostPartIP(address, mask) if err != nil { return fmt.Errorf("failed to release address %s: %v", address.String(), err) } bm, err := a.retrieveBitmask(k, c.Pool) if err != nil { return fmt.Errorf("could not find bitmask in datastore for %s on address %v release from pool %s: %v", k.String(), address, poolID, err) } return bm.Unset(ipToUint64(h)) }
func ipamOption(bridgeName string) libnetwork.NetworkOption { if nw, _, err := ipamutils.ElectInterfaceAddresses(bridgeName); err == nil { ipamV4Conf := &libnetwork.IpamConf{PreferredPool: nw.String()} hip, _ := types.GetHostPartIP(nw.IP, nw.Mask) if hip.IsGlobalUnicast() { ipamV4Conf.Gateway = nw.IP.String() } return libnetwork.NetworkOptionIpam("default", "", []*libnetwork.IpamConf{ipamV4Conf}, nil) } return nil }
func getAddressRange(pool string) (*AddressRange, error) { ip, nw, err := net.ParseCIDR(pool) if err != nil { return nil, ipamapi.ErrInvalidSubPool } lIP, e := types.GetHostPartIP(nw.IP, nw.Mask) if e != nil { return nil, fmt.Errorf("failed to compute range's lowest ip address: %v", e) } bIP, e := types.GetBroadcastIP(nw.IP, nw.Mask) if e != nil { return nil, fmt.Errorf("failed to compute range's broadcast ip address: %v", e) } hIP, e := types.GetHostPartIP(bIP, nw.Mask) if e != nil { return nil, fmt.Errorf("failed to compute range's highest ip address: %v", e) } nw.IP = ip return &AddressRange{nw, ipToUint64(types.GetMinimalIP(lIP)), ipToUint64(types.GetMinimalIP(hIP))}, nil }
// ReleaseAddress releases the address from the specified pool ID func (a *Allocator) ReleaseAddress(poolID string, address net.IP) error { k := SubnetKey{} if err := k.FromString(poolID); err != nil { return types.BadRequestErrorf("invalid pool id: %s", poolID) } cfg, err := a.getPoolsConfig(k.AddressSpace) if err != nil { return err } cfg.Lock() p, ok := cfg.subnets[k] if !ok { cfg.Unlock() return ipamapi.ErrBadPool } if address == nil || !p.Pool.Contains(address) { cfg.Unlock() return ipamapi.ErrInvalidRequest } c := p for c.Range != nil { k = c.ParentKey c = cfg.subnets[k] } cfg.Unlock() mask := p.Pool.Mask if p.Range != nil { mask = p.Range.Sub.Mask } h, err := types.GetHostPartIP(address, mask) if err != nil { return fmt.Errorf("failed to release address %s: %v", address.String(), err) } bm, err := cfg.alloc.retrieveBitmask(cfg.ds, k, c.Pool) if err != nil { return fmt.Errorf("could not find bitmask in datastore for %s on address %v release from pool %s: %v", k.String(), address, poolID, err) } return bm.Unset(ipToUint32(h)) }
// Release allows releasing the address from the specified address space func (a *Allocator) Release(addrSpace AddressSpace, address net.IP) { var ( space *bitseq.Handle sub *net.IPNet ) if address == nil { log.Debugf("Requested to remove nil address from address space %s", addrSpace) return } ver := getAddressVersion(address) if ver == v4 { address = address.To4() } // Find the subnet containing the address for _, subKey := range a.getSubnetList(addrSpace, ver) { sub = subKey.canonicalChildSubnet() if sub.Contains(address) { a.Lock() space = a.addresses[subKey] a.Unlock() break } } if space == nil { log.Debugf("Could not find subnet on address space %s containing %s on release", addrSpace, address.String()) return } // Retrieve correspondent ordinal in the subnet hostPart, err := types.GetHostPartIP(address, sub.Mask) if err != nil { log.Warnf("Failed to release address %s on address space %s because of internal error: %v", address.String(), addrSpace, err) return } ordinal := ipToUint32(hostPart) // Release it if err := space.Unset(ordinal); err != nil { log.Warnf("Failed to release address %s on address space %s because of internal error: %v", address.String(), addrSpace, err) } }
func (a *Allocator) getAddress(nw *net.IPNet, bitmask *bitseq.Handle, prefAddress net.IP, ipr *AddressRange) (net.IP, error) { var ( ordinal uint64 err error base *net.IPNet ) base = types.GetIPNetCopy(nw) if bitmask.Unselected() <= 0 { return nil, ipamapi.ErrNoAvailableIPs } if ipr == nil && prefAddress == nil { ordinal, err = bitmask.SetAny() } else if prefAddress != nil { hostPart, e := types.GetHostPartIP(prefAddress, base.Mask) if e != nil { return nil, types.InternalErrorf("failed to allocate requested address %s: %v", prefAddress.String(), e) } ordinal = ipToUint64(types.GetMinimalIP(hostPart)) err = bitmask.Set(ordinal) } else { ordinal, err = bitmask.SetAnyInRange(ipr.Start, ipr.End) } switch err { case nil: // Convert IP ordinal for this subnet into IP address return generateAddress(ordinal, base), nil case bitseq.ErrBitAllocated: return nil, ipamapi.ErrIPAlreadyAllocated case bitseq.ErrNoBitAvailable: return nil, ipamapi.ErrNoAvailableIPs default: return nil, err } }
func initBridgeDriver(controller libnetwork.NetworkController, config *Config) error { if n, err := controller.NetworkByName("bridge"); err == nil { if err = n.Delete(); err != nil { return fmt.Errorf("could not delete the default bridge network: %v", err) } } bridgeName := bridge.DefaultBridgeName if config.Bridge.Iface != "" { bridgeName = config.Bridge.Iface } netOption := map[string]string{ bridge.BridgeName: bridgeName, bridge.DefaultBridge: strconv.FormatBool(true), netlabel.DriverMTU: strconv.Itoa(config.Mtu), bridge.EnableIPMasquerade: strconv.FormatBool(config.Bridge.EnableIPMasq), bridge.EnableICC: strconv.FormatBool(config.Bridge.InterContainerCommunication), } // --ip processing if config.Bridge.DefaultIP != nil { netOption[bridge.DefaultBindingIP] = config.Bridge.DefaultIP.String() } ipamV4Conf := libnetwork.IpamConf{} ipamV4Conf.AuxAddresses = make(map[string]string) if nw, _, err := ipamutils.ElectInterfaceAddresses(bridgeName); err == nil { ipamV4Conf.PreferredPool = nw.String() hip, _ := types.GetHostPartIP(nw.IP, nw.Mask) if hip.IsGlobalUnicast() { ipamV4Conf.Gateway = nw.IP.String() } } if config.Bridge.IP != "" { ipamV4Conf.PreferredPool = config.Bridge.IP ip, _, err := net.ParseCIDR(config.Bridge.IP) if err != nil { return err } ipamV4Conf.Gateway = ip.String() } else if bridgeName == bridge.DefaultBridgeName && ipamV4Conf.PreferredPool != "" { logrus.Infof("Default bridge (%s) is assigned with an IP address %s. Daemon option --bip can be used to set a preferred IP address", bridgeName, ipamV4Conf.PreferredPool) } if config.Bridge.FixedCIDR != "" { _, fCIDR, err := net.ParseCIDR(config.Bridge.FixedCIDR) if err != nil { return err } ipamV4Conf.SubPool = fCIDR.String() } if config.Bridge.DefaultGatewayIPv4 != nil { ipamV4Conf.AuxAddresses["DefaultGatewayIPv4"] = config.Bridge.DefaultGatewayIPv4.String() } var ( ipamV6Conf *libnetwork.IpamConf deferIPv6Alloc bool ) if config.Bridge.FixedCIDRv6 != "" { _, fCIDRv6, err := net.ParseCIDR(config.Bridge.FixedCIDRv6) if err != nil { return err } // In case user has specified the daemon flag --fixed-cidr-v6 and the passed network has // at least 48 host bits, we need to guarantee the current behavior where the containers' // IPv6 addresses will be constructed based on the containers' interface MAC address. // We do so by telling libnetwork to defer the IPv6 address allocation for the endpoints // on this network until after the driver has created the endpoint and returned the // constructed address. Libnetwork will then reserve this address with the ipam driver. ones, _ := fCIDRv6.Mask.Size() deferIPv6Alloc = ones <= 80 if ipamV6Conf == nil { ipamV6Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)} } ipamV6Conf.PreferredPool = fCIDRv6.String() } if config.Bridge.DefaultGatewayIPv6 != nil { if ipamV6Conf == nil { ipamV6Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)} } ipamV6Conf.AuxAddresses["DefaultGatewayIPv6"] = config.Bridge.DefaultGatewayIPv6.String() } v4Conf := []*libnetwork.IpamConf{&ipamV4Conf} v6Conf := []*libnetwork.IpamConf{} if ipamV6Conf != nil { v6Conf = append(v6Conf, ipamV6Conf) } // Initialize default network on "bridge" with the same name _, err := controller.NewNetwork("bridge", "bridge", libnetwork.NetworkOptionGeneric(options.Generic{ netlabel.GenericData: netOption, netlabel.EnableIPv6: config.Bridge.EnableIPv6, }), libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil), libnetwork.NetworkOptionDeferIPv6Alloc(deferIPv6Alloc)) if err != nil { return fmt.Errorf("Error creating default \"bridge\" network: %v", err) } return nil }
func initBridgeDriver(controller libnetwork.NetworkController, config *Config) error { if n, err := controller.NetworkByName("bridge"); err == nil { if err = n.Delete(); err != nil { return fmt.Errorf("could not delete the default bridge network: %v", err) } } bridgeName := bridge.DefaultBridgeName if config.bridgeConfig.Iface != "" { bridgeName = config.bridgeConfig.Iface } netOption := map[string]string{ bridge.BridgeName: bridgeName, bridge.DefaultBridge: strconv.FormatBool(true), netlabel.DriverMTU: strconv.Itoa(config.Mtu), bridge.EnableICC: strconv.FormatBool(config.bridgeConfig.InterContainerCommunication), } // --ip processing if config.bridgeConfig.DefaultIP != nil { netOption[bridge.DefaultBindingIP] = config.bridgeConfig.DefaultIP.String() } var ipamV4Conf *libnetwork.IpamConf ipamV4Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)} nwList, _, err := netutils.ElectInterfaceAddresses(bridgeName) if err != nil { return errors.Wrap(err, "list bridge addresses failed") } nw := nwList[0] if len(nwList) > 1 && config.bridgeConfig.FixedCIDR != "" { _, fCIDR, err := net.ParseCIDR(config.bridgeConfig.FixedCIDR) if err != nil { return errors.Wrap(err, "parse CIDR failed") } // Iterate through in case there are multiple addresses for the bridge for _, entry := range nwList { if fCIDR.Contains(entry.IP) { nw = entry break } } } ipamV4Conf.PreferredPool = lntypes.GetIPNetCanonical(nw).String() hip, _ := lntypes.GetHostPartIP(nw.IP, nw.Mask) if hip.IsGlobalUnicast() { ipamV4Conf.Gateway = nw.IP.String() } if config.bridgeConfig.IP != "" { ipamV4Conf.PreferredPool = config.bridgeConfig.IP ip, _, err := net.ParseCIDR(config.bridgeConfig.IP) if err != nil { return err } ipamV4Conf.Gateway = ip.String() } else if bridgeName == bridge.DefaultBridgeName && ipamV4Conf.PreferredPool != "" { logrus.Infof("Default bridge (%s) is assigned with an IP address %s. Daemon option --bip can be used to set a preferred IP address", bridgeName, ipamV4Conf.PreferredPool) } if config.bridgeConfig.FixedCIDR != "" { _, fCIDR, err := net.ParseCIDR(config.bridgeConfig.FixedCIDR) if err != nil { return err } ipamV4Conf.SubPool = fCIDR.String() } if config.bridgeConfig.DefaultGatewayIPv4 != nil { ipamV4Conf.AuxAddresses["DefaultGatewayIPv4"] = config.bridgeConfig.DefaultGatewayIPv4.String() } v4Conf := []*libnetwork.IpamConf{ipamV4Conf} v6Conf := []*libnetwork.IpamConf{} // Initialize default network on "bridge" with the same name _, err = controller.NewNetwork("bridge", "bridge", "", libnetwork.NetworkOptionDriverOpts(netOption), libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil), libnetwork.NetworkOptionDeferIPv6Alloc(false)) if err != nil { return fmt.Errorf("Error creating default 'bridge' network: %v", err) } return nil }
func initBridgeDriver(controller libnetwork.NetworkController, config *Config) error { bridgeName := bridge.DefaultBridgeName if config.bridgeConfig.Iface != "" { bridgeName = config.bridgeConfig.Iface } netOption := map[string]string{ bridge.BridgeName: bridgeName, bridge.DefaultBridge: strconv.FormatBool(true), netlabel.DriverMTU: strconv.Itoa(config.Mtu), bridge.EnableIPMasquerade: strconv.FormatBool(config.bridgeConfig.EnableIPMasq), bridge.EnableICC: strconv.FormatBool(config.bridgeConfig.InterContainerCommunication), } // --ip processing if config.bridgeConfig.DefaultIP != nil { netOption[bridge.DefaultBindingIP] = config.bridgeConfig.DefaultIP.String() } var ( ipamV4Conf *libnetwork.IpamConf ipamV6Conf *libnetwork.IpamConf ) ipamV4Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)} nwList, nw6List, err := netutils.ElectInterfaceAddresses(bridgeName) if err != nil { return errors.Wrap(err, "list bridge addresses failed") } nw := nwList[0] if len(nwList) > 1 && config.bridgeConfig.FixedCIDR != "" { _, fCIDR, err := net.ParseCIDR(config.bridgeConfig.FixedCIDR) if err != nil { return errors.Wrap(err, "parse CIDR failed") } // Iterate through in case there are multiple addresses for the bridge for _, entry := range nwList { if fCIDR.Contains(entry.IP) { nw = entry break } } } ipamV4Conf.PreferredPool = lntypes.GetIPNetCanonical(nw).String() hip, _ := lntypes.GetHostPartIP(nw.IP, nw.Mask) if hip.IsGlobalUnicast() { ipamV4Conf.Gateway = nw.IP.String() } if config.bridgeConfig.IP != "" { ipamV4Conf.PreferredPool = config.bridgeConfig.IP ip, _, err := net.ParseCIDR(config.bridgeConfig.IP) if err != nil { return err } ipamV4Conf.Gateway = ip.String() } else if bridgeName == bridge.DefaultBridgeName && ipamV4Conf.PreferredPool != "" { logrus.Infof("Default bridge (%s) is assigned with an IP address %s. Daemon option --bip can be used to set a preferred IP address", bridgeName, ipamV4Conf.PreferredPool) } if config.bridgeConfig.FixedCIDR != "" { _, fCIDR, err := net.ParseCIDR(config.bridgeConfig.FixedCIDR) if err != nil { return err } ipamV4Conf.SubPool = fCIDR.String() } if config.bridgeConfig.DefaultGatewayIPv4 != nil { ipamV4Conf.AuxAddresses["DefaultGatewayIPv4"] = config.bridgeConfig.DefaultGatewayIPv4.String() } var deferIPv6Alloc bool if config.bridgeConfig.FixedCIDRv6 != "" { _, fCIDRv6, err := net.ParseCIDR(config.bridgeConfig.FixedCIDRv6) if err != nil { return err } // In case user has specified the daemon flag --fixed-cidr-v6 and the passed network has // at least 48 host bits, we need to guarantee the current behavior where the containers' // IPv6 addresses will be constructed based on the containers' interface MAC address. // We do so by telling libnetwork to defer the IPv6 address allocation for the endpoints // on this network until after the driver has created the endpoint and returned the // constructed address. Libnetwork will then reserve this address with the ipam driver. ones, _ := fCIDRv6.Mask.Size() deferIPv6Alloc = ones <= 80 if ipamV6Conf == nil { ipamV6Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)} } ipamV6Conf.PreferredPool = fCIDRv6.String() // In case the --fixed-cidr-v6 is specified and the current docker0 bridge IPv6 // address belongs to the same network, we need to inform libnetwork about it, so // that it can be reserved with IPAM and it will not be given away to somebody else for _, nw6 := range nw6List { if fCIDRv6.Contains(nw6.IP) { ipamV6Conf.Gateway = nw6.IP.String() break } } } if config.bridgeConfig.DefaultGatewayIPv6 != nil { if ipamV6Conf == nil { ipamV6Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)} } ipamV6Conf.AuxAddresses["DefaultGatewayIPv6"] = config.bridgeConfig.DefaultGatewayIPv6.String() } v4Conf := []*libnetwork.IpamConf{ipamV4Conf} v6Conf := []*libnetwork.IpamConf{} if ipamV6Conf != nil { v6Conf = append(v6Conf, ipamV6Conf) } // Initialize default network on "bridge" with the same name _, err = controller.NewNetwork("bridge", "bridge", "", libnetwork.NetworkOptionEnableIPv6(config.bridgeConfig.EnableIPv6), libnetwork.NetworkOptionDriverOpts(netOption), libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil), libnetwork.NetworkOptionDeferIPv6Alloc(deferIPv6Alloc)) if err != nil { return fmt.Errorf("Error creating default \"bridge\" network: %v", err) } return nil }
func initBridgeDriver(controller libnetwork.NetworkController, config *Config) error { if n, err := controller.NetworkByName("bridge"); err == nil { if err = n.Delete(); err != nil { return fmt.Errorf("could not delete the default bridge network: %v", err) } } bridgeName := bridge.DefaultBridgeName if config.Bridge.Iface != "" { bridgeName = config.Bridge.Iface } netOption := map[string]string{ bridge.BridgeName: bridgeName, bridge.DefaultBridge: strconv.FormatBool(true), netlabel.DriverMTU: strconv.Itoa(config.Mtu), bridge.EnableIPMasquerade: strconv.FormatBool(config.Bridge.EnableIPMasq), bridge.EnableICC: strconv.FormatBool(config.Bridge.InterContainerCommunication), } // --ip processing if config.Bridge.DefaultIP != nil { netOption[bridge.DefaultBindingIP] = config.Bridge.DefaultIP.String() } ipamV4Conf := libnetwork.IpamConf{} ipamV4Conf.AuxAddresses = make(map[string]string) if nw, _, err := ipamutils.ElectInterfaceAddresses(bridgeName); err == nil { ipamV4Conf.PreferredPool = nw.String() hip, _ := types.GetHostPartIP(nw.IP, nw.Mask) if hip.IsGlobalUnicast() { ipamV4Conf.Gateway = nw.IP.String() } } if config.Bridge.IP != "" { ipamV4Conf.PreferredPool = config.Bridge.IP ip, _, err := net.ParseCIDR(config.Bridge.IP) if err != nil { return err } ipamV4Conf.Gateway = ip.String() } if config.Bridge.FixedCIDR != "" { _, fCIDR, err := net.ParseCIDR(config.Bridge.FixedCIDR) if err != nil { return err } ipamV4Conf.SubPool = fCIDR.String() } if config.Bridge.DefaultGatewayIPv4 != nil { ipamV4Conf.AuxAddresses["DefaultGatewayIPv4"] = config.Bridge.DefaultGatewayIPv4.String() } var ipamV6Conf *libnetwork.IpamConf if config.Bridge.FixedCIDRv6 != "" { _, fCIDRv6, err := net.ParseCIDR(config.Bridge.FixedCIDRv6) if err != nil { return err } if ipamV6Conf == nil { ipamV6Conf = &libnetwork.IpamConf{} } ipamV6Conf.PreferredPool = fCIDRv6.String() } if config.Bridge.DefaultGatewayIPv6 != nil { if ipamV6Conf == nil { ipamV6Conf = &libnetwork.IpamConf{} } ipamV6Conf.AuxAddresses["DefaultGatewayIPv6"] = config.Bridge.DefaultGatewayIPv6.String() } v4Conf := []*libnetwork.IpamConf{&ipamV4Conf} v6Conf := []*libnetwork.IpamConf{} if ipamV6Conf != nil { v6Conf = append(v6Conf, ipamV6Conf) } // Initialize default network on "bridge" with the same name _, err := controller.NewNetwork("bridge", "bridge", libnetwork.NetworkOptionGeneric(options.Generic{ netlabel.GenericData: netOption, netlabel.EnableIPv6: config.Bridge.EnableIPv6, }), libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf)) if err != nil { return fmt.Errorf("Error creating default \"bridge\" network: %v", err) } return nil }