Repository: moby/moby
File: daemon/libnetwork/ipams/defaultipam/allocator.go (Go)

Code before:
	log.G(context.TODO()).Debugf("RequestPool: %+v", req)

	parseErr := func(err error) error {
		return types.InternalErrorf("failed to parse pool request for address space %q pool %q subpool %q: %v", req.AddressSpace, req.Pool, req.SubPool, err)
	}

	if req.AddressSpace == "" {
		return ipamapi.AllocatedPool{}, parseErr(ipamapi.ErrInvalidAddressSpace)
	}
	aSpace, err := a.getAddrSpace(req.AddressSpace, req.V6)
	if err != nil {
		return ipamapi.AllocatedPool{}, err
	}

	k := PoolID{AddressSpace: req.AddressSpace}

	subnetSize := 0

	if req.Pool != "" {
		if strings.HasPrefix(req.Pool, "/") {
			if req.V6 {
				req.Pool = "::" + req.Pool
			} else {
				req.Pool = "0.0.0.0" + req.Pool
			}
		}

		prefix, err := netip.ParsePrefix(req.Pool)
		if err != nil {
			return ipamapi.AllocatedPool{}, parseErr(ipamapi.ErrInvalidPool)
		}

		if prefix.Addr().IsUnspecified() {
			// If the prefix is unspecified, we're only interested in the prefix size.
			// We'll attempt to use the specified size to allocate a subnet from the
			// predefined pools.
			req.Pool = ""

			if req.Options == nil {
				req.Options = make(map[string]string)
			}

			if prefix.Bits() > 0 {
				subnetSize = prefix.Bits()
			}
		} else {
			k.Subnet = prefix
		}
	}

	if req.Pool == "" && req.SubPool != "" {

Review comment (suggestion):
I think `req.Pool` will already have been normalised in `Daemon.createNetwork` to include an unspecified address, in cases where just a prefix length can be specified? (So, perhaps the allocator doesn't need to handle this? But I might be missing something.)

Code after:

	parseErr := func(err error) error {
		return types.InternalErrorf("failed to parse pool request for address space %q pool %q subpool %q: %v", req.AddressSpace, req.Pool, req.SubPool, err)
	}

	if req.AddressSpace == "" {
		return ipamapi.AllocatedPool{}, parseErr(ipamapi.ErrInvalidAddressSpace)
	}
	aSpace, err := a.getAddrSpace(req.AddressSpace, req.V6)
	if err != nil {
		return ipamapi.AllocatedPool{}, err
	}

	k := PoolID{AddressSpace: req.AddressSpace}

	prefixLength := 0

	if req.Pool != "" {
		prefix, err := netip.ParsePrefix(req.Pool)
		if err != nil {
			return ipamapi.AllocatedPool{}, parseErr(ipamapi.ErrInvalidPool)
		}

		if prefix.Addr().IsUnspecified() {
			// If the prefix is unspecified, we're only interested in the prefix size.
			// We'll attempt to use the specified size to allocate a subnet from the
			// predefined pools.
			req.Pool = ""

			if prefix.Bits() > 0 {
				prefixLength = prefix.Bits()
			}
		} else {
			k.Subnet = prefix
		}
	}

	if req.Pool == "" && req.SubPool != "" {
		return ipamapi.AllocatedPool{}, parseErr(ipamapi.ErrInvalidSubPool)
	}

	if req.Pool == "" {
		if k.Subnet, err = aSpace.allocatePredefinedPool(req.Exclude, prefixLength); err != nil {
			return ipamapi.AllocatedPool{}, err
		}
		return ipamapi.AllocatedPool{PoolID: k.String(), Pool: k.Subnet}, nil
	}

	if req.SubPool != "" {
		if k.ChildSubnet, err = netip.ParsePrefix(req.SubPool); err != nil {
			return ipamapi.AllocatedPool{}, types.InternalErrorf("invalid pool request: %v", ipamapi.ErrInvalidSubPool)