libnetwork/ipam: assorted cleanup and refactor
### libnetwork/ipams/null: use consts for fixed values

### libnetwork/ipam: Allocator.RequestPool: make parseErr only handle errors

This makes it slightly more readable to see what's returned in each of
the code-paths. Also move validation of pool/subpool earlier in the
function.

### libnetwork/ipam: Allocator.RequestPool: mark options arg as unused

The options are unused, other than for debug-logging, which made it look
as if they were actually consumed anywhere, but they aren't.

### libnetwork/ipam: Allocator.RequestPool: name args, output vars

network.requestPoolHelper and Allocator.RequestPool have many args and
output vars with generic types. Add names for them to make it easier to
grasp what's what.

### libnetwork/ipam: PoolID.String(): don't use fmt.Sprintf

As this function may be called repeatedly to convert to/from a string,
it may be worth optimizing it a bit. Adding a minimal Benchmark for
it as well.

Before/after:

    BenchmarkPoolIDToString-10   2842830   424.3 ns/op   232 B/op  12 allocs/op
    BenchmarkPoolIDToString-10   7176738   166.8 ns/op   112 B/op   7 allocs/op


libnetwork/ipam: move PoolID.FromString() to a PoolIDFromString() func

This makes it easier to consume, without first having to create an empty
PoolID.

Performance is the same:

    BenchmarkPoolIDFromString-10   6100345   196.5 ns/op  112 B/op   3 allocs/op
    BenchmarkPoolIDFromString-10   6252750   192.0 ns/op  112 B/op   3 allocs/op

Note that I opted not to change the return-type to a pointer, as that seems
to perform less;

    BenchmarkPoolIDFromString-10   6252750   192.0 ns/op  112 B/op   3 allocs/op
    BenchmarkPoolIDFromString-10   5288682   226.6 ns/op  192 B/op   4 allocs/op


### libnetwork: network.IpamConfig, network.IpamInfo: name output vars

Both functions have multiple output vars with generic types, which made
it hard to grasp what's what.


### libnetwork: network.requestPoolHelper: don't defer in a loop

This function intentionally holds a lock / lease on address-pools to
prevent trying the same pool repeatedly.

Let's try to make this logic slightly more transparent, and prevent
defining defers in a loop. Releasing all the pools in a singe defer
also allows us to get the network-name once, which prevents locking
and unlocking the network for each iteration.

### libnetwork: network.requestPoolHelper: remove dead code

This code was only run if no preferred pool was specified, however,
since [libnetwork#1162][2], the function would already return early
if a preferred pools was set (and the overlap check to be skipped),
so this was now just dead code.

[2]: https://github.com/moby/libnetwork/commit/9cc3385f4421ff00a5b7dfc2d9ad44289aa21c85


### libnetwork: network.requestPoolHelper: slightly optimize order of checks

Check the preferredPool first, as other checks could be doing more
(such as locking, or validating / parsing). Also adding a note, as
it's unclear why we're 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 condition to return early.

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.

To make this code slightly more transparent, this patch also inlines
the "types.IsIPNetValid" function, as it's not used anywhere else,
and inlining it makes it more visible.

[1]: https://github.com/moby/libnetwork/commit/5ca79d6b87873264516323a7b76f0af7d0298492#diff-bdcd879439d041827d334846f9aba01de6e3683ed8fdd01e63917dae6df23846



**- How to verify it**

**- Description for the changelog**
<!--
Write a short (one line) summary that describes the changes in this
pull request for inclusion in the changelog:
-->


**- A picture of a cute animal (not mandatory but encouraged)**


libnetwork/ipamapi/contract.go
// Package ipamapi specifies the contract the IPAM service (built-in or remote) needs to satisfy.
package ipamapi

import (
	"net"

	"github.com/docker/docker/libnetwork/types"
)

// IPAM plugin types
const (
	// DefaultIPAM is the name of the built-in default ipam driver
	DefaultIPAM = "default"
	// NullIPAM is the name of the built-in null ipam driver
	NullIPAM = "null"
	// PluginEndpointType represents the Endpoint Type used by Plugin system
	PluginEndpointType = "IpamDriver"
	// RequestAddressType represents the Address Type used when requesting an address
	RequestAddressType = "RequestAddressType"
)

// Registerer provides a callback interface for registering IPAM instances into libnetwork.
type Registerer interface {
	// RegisterIpamDriver provides a way for drivers to dynamically register with libnetwork
	RegisterIpamDriver(name string, driver Ipam) error
	// RegisterIpamDriverWithCapabilities provides a way for drivers to dynamically register with libnetwork and specify capabilities
	RegisterIpamDriverWithCapabilities(name string, driver Ipam, capability *Capability) error
}

// Well-known errors returned by IPAM
var (
	ErrIpamInternalError   = types.InternalErrorf("IPAM Internal Error")
	ErrInvalidAddressSpace = types.BadRequestErrorf("Invalid Address Space")
	ErrInvalidPool         = types.BadRequestErrorf("Invalid Address Pool")
	ErrInvalidSubPool      = types.BadRequestErrorf("Invalid Address SubPool")
	ErrInvalidRequest      = types.BadRequestErrorf("Invalid Request")
	ErrPoolNotFound        = types.BadRequestErrorf("Address Pool not found")
	ErrOverlapPool         = types.ForbiddenErrorf("Address pool overlaps with existing pool on this address space")
	ErrNoAvailablePool     = types.NoServiceErrorf("No available pool")
	ErrNoAvailableIPs      = types.NoServiceErrorf("No available addresses on this pool")
	ErrNoIPReturned        = types.NoServiceErrorf("No address returned")
	ErrIPAlreadyAllocated  = types.ForbiddenErrorf("Address already in use")
	ErrIPOutOfRange        = types.BadRequestErrorf("Requested address is out of range")
	ErrPoolOverlap         = types.ForbiddenErrorf("Pool overlaps with other one on this address space")
	ErrBadPool             = types.BadRequestErrorf("Address space does not contain specified address pool")
)

// Ipam represents the interface the IPAM service plugins must implement
// in order to allow injection/modification of IPAM database.
type Ipam interface {
	// GetDefaultAddressSpaces returns the default local and global address spaces for this ipam
	GetDefaultAddressSpaces() (string, string, error)
	// RequestPool returns an address pool along with its unique id. Address space is a mandatory field
	// which denotes a set of non-overlapping pools. pool describes the pool of addresses in CIDR notation.
	// subpool indicates a smaller range of addresses from the pool, for now it is specified in CIDR notation.
	// Both pool and subpool are non mandatory fields. When they are not specified, Ipam driver may choose to
	// return a self chosen pool for this request. In such case the v6 flag needs to be set appropriately so
	// that the driver would return the expected ip version pool.
	RequestPool(addressSpace, pool, subPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error)
	// ReleasePool releases the address pool identified by the passed id
	ReleasePool(poolID string) error
	// RequestAddress request an address from the specified pool ID. Input options or required IP can be passed.
	RequestAddress(string, net.IP, map[string]string) (*net.IPNet, map[string]string, error)
	// ReleaseAddress releases the address from the specified pool ID.
	ReleaseAddress(string, net.IP) error

	// IsBuiltIn returns true if it is a built-in driver.
	IsBuiltIn() bool
}

// Capability represents the requirements and capabilities of the IPAM driver
type Capability struct {
	// Whether on address request, libnetwork must
	// specify the endpoint MAC address
	RequiresMACAddress bool
	// Whether of daemon start, libnetwork must replay the pool
	// request and the address request for current local networks
	RequiresRequestReplay bool
}

// Package ipamapi specifies the contract the IPAM service (built-in or remote) needs to satisfy.
package ipamapi

import (
	"net"

	"github.com/docker/docker/libnetwork/types"
)

// IPAM plugin types
const (
	// DefaultIPAM is the name of the built-in default ipam driver
	DefaultIPAM = "default"
	// NullIPAM is the name of the built-in null ipam driver
	NullIPAM = "null"
	// PluginEndpointType represents the Endpoint Type used by Plugin system
	PluginEndpointType = "IpamDriver"
	// RequestAddressType represents the Address Type used when requesting an address
	RequestAddressType = "RequestAddressType"
)

// Registerer provides a callback interface for registering IPAM instances into libnetwork.
type Registerer interface {
	// RegisterIpamDriver provides a way for drivers to dynamically register with libnetwork
	RegisterIpamDriver(name string, driver Ipam) error
	// RegisterIpamDriverWithCapabilities provides a way for drivers to dynamically register with libnetwork and specify capabilities
	RegisterIpamDriverWithCapabilities(name string, driver Ipam, capability *Capability) error
}

// Well-known errors returned by IPAM
var (
	ErrIpamInternalError   = types.InternalErrorf("IPAM Internal Error")
	ErrInvalidAddressSpace = types.BadRequestErrorf("Invalid Address Space")
	ErrInvalidPool         = types.BadRequestErrorf("Invalid Address Pool")
	ErrInvalidSubPool      = types.BadRequestErrorf("Invalid Address SubPool")
	ErrInvalidRequest      = types.BadRequestErrorf("Invalid Request")
	ErrPoolNotFound        = types.BadRequestErrorf("Address Pool not found")
	ErrOverlapPool         = types.ForbiddenErrorf("Address pool overlaps with existing pool on this address space")
	ErrNoAvailablePool     = types.NoServiceErrorf("No available pool")
	ErrNoAvailableIPs      = types.NoServiceErrorf("No available addresses on this pool")
	ErrNoIPReturned        = types.NoServiceErrorf("No address returned")
	ErrIPAlreadyAllocated  = types.ForbiddenErrorf("Address already in use")
	ErrIPOutOfRange        = types.BadRequestErrorf("Requested address is out of range")
	ErrPoolOverlap         = types.ForbiddenErrorf("Pool overlaps with other one on this address space")
	ErrBadPool             = types.BadRequestErrorf("Address space does not contain specified address pool")
)

// Ipam represents the interface the IPAM service plugins must implement
// in order to allow injection/modification of IPAM database.
type Ipam interface {
	// GetDefaultAddressSpaces returns the default local and global address spaces for this ipam
	GetDefaultAddressSpaces() (string, string, error)
	// RequestPool returns an address pool along with its unique id. Address space is a mandatory field
	// which denotes a set of non-overlapping pools. requestedPool describes the pool of addresses in CIDR notation.
	// requestedSubPool indicates a smaller range of addresses from the pool, for now it is specified in CIDR notation.
	// Both requestedPool and requestedSubPool are non-mandatory fields. When they are not specified, Ipam driver may choose to
	// return a self chosen pool for this request. In such case the v6 flag needs to be set appropriately so
	// that the driver would return the expected ip version pool.
	RequestPool(addressSpace, requestedPool, requestedSubPool string, options map[string]string, v6 bool) (poolID string, pool *net.IPNet, meta map[string]string, err error)
	// ReleasePool releases the address pool identified by the passed id
	ReleasePool(poolID string) error
	// RequestAddress request an address from the specified pool ID. Input options or required IP can be passed.
	RequestAddress(string, net.IP, map[string]string) (*net.IPNet, map[string]string, error)
	// ReleaseAddress releases the address from the specified pool ID.
	ReleaseAddress(string, net.IP) error

	// IsBuiltIn returns true if it is a built-in driver.
	IsBuiltIn() bool
}

// Capability represents the requirements and capabilities of the IPAM driver
type Capability struct {
	// Whether on address request, libnetwork must
	// specify the endpoint MAC address
	RequiresMACAddress bool
	// Whether of daemon start, libnetwork must replay the pool
	// request and the address request for current local networks
	RequiresRequestReplay bool
}

😭 😂 🙈 

fixed 👍 