mirror of
https://github.com/moby/moby.git
synced 2026-08-03 22:51:03 +00:00
libnet/portmapper: rename, move PortMapper to portallocator
The only viable way to allocate a port is to bind and listen to it. So, the windows PortMapper was really a PortAllocator in disguise. Rename it to OSAllocator and move it to the portallocator package. Signed-off-by: Albin Kerouanton <albinker@gmail.com>
This commit is contained in:
@@ -159,14 +159,14 @@ func (d *driver) CreateEndpoint(ctx context.Context, nid, eid string, ifInfo dri
|
||||
}
|
||||
|
||||
ep.portMapping = epConnectivity.PortBindings
|
||||
ep.portMapping, err = windows.AllocatePorts(n.portMapper, ep.portMapping)
|
||||
ep.portMapping, err = windows.AllocatePorts(n.pa, ep.portMapping)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err != nil {
|
||||
windows.ReleasePorts(n.portMapper, ep.portMapping)
|
||||
windows.ReleasePorts(n.pa, ep.portMapping)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -227,7 +227,7 @@ func (d *driver) DeleteEndpoint(nid, eid string) error {
|
||||
return fmt.Errorf("endpoint id %q not found", eid)
|
||||
}
|
||||
|
||||
windows.ReleasePorts(n.portMapper, ep.portMapping)
|
||||
windows.ReleasePorts(n.pa, ep.portMapping)
|
||||
|
||||
n.deleteEndpoint(eid)
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
"github.com/moby/moby/v2/daemon/libnetwork/driverapi"
|
||||
"github.com/moby/moby/v2/daemon/libnetwork/drivers/overlay"
|
||||
"github.com/moby/moby/v2/daemon/libnetwork/netlabel"
|
||||
"github.com/moby/moby/v2/daemon/libnetwork/portmapper"
|
||||
"github.com/moby/moby/v2/daemon/libnetwork/portallocator"
|
||||
"github.com/moby/moby/v2/daemon/libnetwork/types"
|
||||
)
|
||||
|
||||
@@ -50,7 +50,7 @@ type network struct {
|
||||
initErr error
|
||||
subnets []*subnet
|
||||
secure bool
|
||||
portMapper *portmapper.PortMapper
|
||||
pa *portallocator.OSAllocator
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
@@ -86,11 +86,11 @@ func (d *driver) CreateNetwork(ctx context.Context, id string, option map[string
|
||||
}
|
||||
|
||||
n := &network{
|
||||
id: id,
|
||||
driver: d,
|
||||
endpoints: endpointTable{},
|
||||
subnets: []*subnet{},
|
||||
portMapper: portmapper.New(),
|
||||
id: id,
|
||||
driver: d,
|
||||
endpoints: endpointTable{},
|
||||
subnets: []*subnet{},
|
||||
pa: portallocator.New(),
|
||||
}
|
||||
|
||||
genData, ok := option[netlabel.GenericData].(map[string]string)
|
||||
|
||||
@@ -10,20 +10,20 @@ import (
|
||||
"net"
|
||||
|
||||
"github.com/containerd/log"
|
||||
"github.com/moby/moby/v2/daemon/libnetwork/portmapper"
|
||||
"github.com/moby/moby/v2/daemon/libnetwork/portallocator"
|
||||
"github.com/moby/moby/v2/daemon/libnetwork/types"
|
||||
)
|
||||
|
||||
const maxAllocatePortAttempts = 10
|
||||
|
||||
// AllocatePorts allocates ports specified in bindings from the portMapper
|
||||
func AllocatePorts(portMapper *portmapper.PortMapper, bindings []types.PortBinding) ([]types.PortBinding, error) {
|
||||
// AllocatePorts allocates ports specified in bindings from the port allocator.
|
||||
func AllocatePorts(pa *portallocator.OSAllocator, bindings []types.PortBinding) ([]types.PortBinding, error) {
|
||||
bs := make([]types.PortBinding, 0, len(bindings))
|
||||
for _, c := range bindings {
|
||||
b, err := allocatePort(portMapper, c)
|
||||
b, err := allocatePort(pa, c)
|
||||
if err != nil {
|
||||
// On allocation failure, release previously allocated ports. On cleanup error, just log a warning message
|
||||
if cuErr := ReleasePorts(portMapper, bs); cuErr != nil {
|
||||
if cuErr := ReleasePorts(pa, bs); cuErr != nil {
|
||||
log.G(context.TODO()).Warnf("Upon allocation failure for %v, failed to clear previously allocated port bindings: %v", b, cuErr)
|
||||
}
|
||||
return nil, err
|
||||
@@ -33,9 +33,9 @@ func AllocatePorts(portMapper *portmapper.PortMapper, bindings []types.PortBindi
|
||||
return bs, nil
|
||||
}
|
||||
|
||||
func allocatePort(portMapper *portmapper.PortMapper, bnd types.PortBinding) (types.PortBinding, error) {
|
||||
func allocatePort(pa *portallocator.OSAllocator, bnd types.PortBinding) (types.PortBinding, error) {
|
||||
// Windows does not support a host ip for port bindings (this is validated in ConvertPortBindings()).
|
||||
// If the HostIP is nil, force it to be 0.0.0.0 for use as the key in portMapper.
|
||||
// If the HostIP is nil, force it to be 0.0.0.0 for use as the key in the port allocator.
|
||||
if bnd.HostIP == nil {
|
||||
bnd.HostIP = net.IPv4zero
|
||||
}
|
||||
@@ -49,7 +49,7 @@ func allocatePort(portMapper *portmapper.PortMapper, bnd types.PortBinding) (typ
|
||||
var allocatedPort int
|
||||
var err error
|
||||
for i := 0; i < maxAllocatePortAttempts; i++ {
|
||||
allocatedPort, err = portMapper.MapRange(bnd.HostIP, bnd.Proto, int(bnd.HostPort), int(bnd.HostPortEnd))
|
||||
allocatedPort, err = pa.AllocateHostPort(bnd.HostIP, bnd.Proto, int(bnd.HostPort), int(bnd.HostPortEnd))
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
@@ -70,13 +70,13 @@ func allocatePort(portMapper *portmapper.PortMapper, bnd types.PortBinding) (typ
|
||||
return bnd, nil
|
||||
}
|
||||
|
||||
// ReleasePorts releases ports specified in bindings from the portMapper
|
||||
func ReleasePorts(portMapper *portmapper.PortMapper, bindings []types.PortBinding) error {
|
||||
// ReleasePorts releases ports specified in bindings from the portAlloc
|
||||
func ReleasePorts(pa *portallocator.OSAllocator, bindings []types.PortBinding) error {
|
||||
var errorBuf bytes.Buffer
|
||||
|
||||
// Attempt to release all port bindings, do not stop on failure
|
||||
for _, m := range bindings {
|
||||
if err := releasePort(portMapper, m); err != nil {
|
||||
if err := releasePort(pa, m); err != nil {
|
||||
errorBuf.WriteString(fmt.Sprintf("\ncould not release %v because of %v", m, err))
|
||||
}
|
||||
}
|
||||
@@ -87,6 +87,6 @@ func ReleasePorts(portMapper *portmapper.PortMapper, bindings []types.PortBindin
|
||||
return nil
|
||||
}
|
||||
|
||||
func releasePort(portMapper *portmapper.PortMapper, bnd types.PortBinding) error {
|
||||
return portMapper.Unmap(bnd.HostIP, bnd.Proto, int(bnd.HostPort))
|
||||
func releasePort(pa *portallocator.OSAllocator, bnd types.PortBinding) error {
|
||||
return pa.Deallocate(bnd.HostIP, bnd.Proto, int(bnd.HostPort))
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ import (
|
||||
"github.com/moby/moby/v2/daemon/libnetwork/datastore"
|
||||
"github.com/moby/moby/v2/daemon/libnetwork/driverapi"
|
||||
"github.com/moby/moby/v2/daemon/libnetwork/netlabel"
|
||||
"github.com/moby/moby/v2/daemon/libnetwork/portmapper"
|
||||
"github.com/moby/moby/v2/daemon/libnetwork/portallocator"
|
||||
"github.com/moby/moby/v2/daemon/libnetwork/scope"
|
||||
"github.com/moby/moby/v2/daemon/libnetwork/types"
|
||||
"go.opentelemetry.io/otel"
|
||||
@@ -94,12 +94,12 @@ type hnsEndpoint struct {
|
||||
}
|
||||
|
||||
type hnsNetwork struct {
|
||||
id string
|
||||
created bool
|
||||
config *networkConfiguration
|
||||
endpoints map[string]*hnsEndpoint // key: endpoint id
|
||||
driver *driver // The network's driver
|
||||
portMapper *portmapper.PortMapper
|
||||
id string
|
||||
created bool
|
||||
config *networkConfiguration
|
||||
endpoints map[string]*hnsEndpoint // key: endpoint id
|
||||
driver *driver // The network's driver
|
||||
pa *portallocator.OSAllocator
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
@@ -308,11 +308,11 @@ func (ncfg *networkConfiguration) processIPAM(id string, ipamV4Data, ipamV6Data
|
||||
|
||||
func (d *driver) createNetwork(config *networkConfiguration) *hnsNetwork {
|
||||
network := &hnsNetwork{
|
||||
id: config.ID,
|
||||
endpoints: make(map[string]*hnsEndpoint),
|
||||
config: config,
|
||||
driver: d,
|
||||
portMapper: portmapper.New(),
|
||||
id: config.ID,
|
||||
endpoints: make(map[string]*hnsEndpoint),
|
||||
config: config,
|
||||
driver: d,
|
||||
pa: portallocator.New(),
|
||||
}
|
||||
|
||||
d.Lock()
|
||||
@@ -701,14 +701,14 @@ func (d *driver) CreateEndpoint(ctx context.Context, nid, eid string, ifInfo dri
|
||||
portMapping := epConnectivity.PortBindings
|
||||
|
||||
if n.config.Type == "l2bridge" || n.config.Type == "l2tunnel" {
|
||||
portMapping, err = AllocatePorts(n.portMapper, portMapping)
|
||||
portMapping, err = AllocatePorts(n.pa, portMapping)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err != nil {
|
||||
ReleasePorts(n.portMapper, portMapping)
|
||||
ReleasePorts(n.pa, portMapping)
|
||||
}
|
||||
}()
|
||||
}
|
||||
@@ -823,7 +823,7 @@ func (d *driver) DeleteEndpoint(nid, eid string) error {
|
||||
}
|
||||
|
||||
if n.config.Type == "l2bridge" || n.config.Type == "l2tunnel" {
|
||||
ReleasePorts(n.portMapper, ep.portMapping)
|
||||
ReleasePorts(n.pa, ep.portMapping)
|
||||
}
|
||||
|
||||
n.Lock()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package portmapper
|
||||
package portallocator
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
|
||||
"github.com/containerd/log"
|
||||
"github.com/ishidawataru/sctp"
|
||||
"github.com/moby/moby/v2/daemon/libnetwork/portallocator"
|
||||
"github.com/moby/moby/v2/daemon/libnetwork/types"
|
||||
)
|
||||
|
||||
@@ -22,42 +21,42 @@ var (
|
||||
ErrPortNotMapped = errors.New("port is not mapped")
|
||||
)
|
||||
|
||||
// PortMapper manages the network address translation
|
||||
type PortMapper struct {
|
||||
// OSAllocator allocates ports from the OS by creating listening sockets.
|
||||
type OSAllocator struct {
|
||||
// osListeners stores listening sockets used by active port mappings
|
||||
// to reserve ports from the OS. Outer map is keyed by protocol, and inner
|
||||
// map is keyed by host address and port.
|
||||
osListeners map[types.Protocol]map[netip.AddrPort]io.Closer
|
||||
lock sync.Mutex
|
||||
|
||||
allocator *portallocator.PortAllocator
|
||||
allocator *PortAllocator
|
||||
}
|
||||
|
||||
// New returns a new instance of PortMapper
|
||||
func New() *PortMapper {
|
||||
return &PortMapper{
|
||||
// New returns a new instance of OSAllocator
|
||||
func New() *OSAllocator {
|
||||
return &OSAllocator{
|
||||
osListeners: make(map[types.Protocol]map[netip.AddrPort]io.Closer),
|
||||
allocator: portallocator.Get(),
|
||||
allocator: Get(),
|
||||
}
|
||||
}
|
||||
|
||||
// MapRange maps the specified container transport address to the host's network address and transport port range
|
||||
func (pm *PortMapper) MapRange(hostIP net.IP, proto types.Protocol, hostPortStart, hostPortEnd int) (_ int, retErr error) {
|
||||
pm.lock.Lock()
|
||||
defer pm.lock.Unlock()
|
||||
// AllocateHostPort allocates a port from the OS (by creating a listening socket).
|
||||
func (pa *OSAllocator) AllocateHostPort(hostIP net.IP, proto types.Protocol, hostPortStart, hostPortEnd int) (_ int, retErr error) {
|
||||
pa.lock.Lock()
|
||||
defer pa.lock.Unlock()
|
||||
|
||||
allocatedHostPort, err := pm.allocator.RequestPortInRange(hostIP, proto.String(), hostPortStart, hostPortEnd)
|
||||
allocatedHostPort, err := pa.allocator.RequestPortInRange(hostIP, proto.String(), hostPortStart, hostPortEnd)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer func() {
|
||||
if retErr != nil {
|
||||
pm.allocator.ReleasePort(hostIP, proto.String(), allocatedHostPort)
|
||||
pa.allocator.ReleasePort(hostIP, proto.String(), allocatedHostPort)
|
||||
}
|
||||
}()
|
||||
|
||||
if pm.osListeners[proto] == nil {
|
||||
pm.osListeners[proto] = make(map[netip.AddrPort]io.Closer)
|
||||
if pa.osListeners[proto] == nil {
|
||||
pa.osListeners[proto] = make(map[netip.AddrPort]io.Closer)
|
||||
}
|
||||
|
||||
addr, ok := netip.AddrFromSlice(hostIP)
|
||||
@@ -66,7 +65,7 @@ func (pm *PortMapper) MapRange(hostIP net.IP, proto types.Protocol, hostPortStar
|
||||
}
|
||||
|
||||
hAddrPort := netip.AddrPortFrom(addr, uint16(allocatedHostPort))
|
||||
if _, exists := pm.osListeners[proto][hAddrPort]; exists {
|
||||
if _, exists := pa.osListeners[proto][hAddrPort]; exists {
|
||||
return 0, ErrPortMappedForIP
|
||||
}
|
||||
|
||||
@@ -83,7 +82,7 @@ func (pm *PortMapper) MapRange(hostIP net.IP, proto types.Protocol, hostPortStar
|
||||
return 0, err
|
||||
}
|
||||
|
||||
pm.osListeners[proto][hAddrPort] = osListener
|
||||
pa.osListeners[proto][hAddrPort] = osListener
|
||||
return allocatedHostPort, nil
|
||||
}
|
||||
|
||||
@@ -119,22 +118,22 @@ func allocateHostPort(proto string, hostIP net.IP, hostPort int) (io.Closer, err
|
||||
}
|
||||
}
|
||||
|
||||
// Unmap removes stored mapping for the specified host transport address
|
||||
func (pm *PortMapper) Unmap(hostIP net.IP, proto types.Protocol, hostPort int) error {
|
||||
pm.lock.Lock()
|
||||
defer pm.lock.Unlock()
|
||||
// Deallocate removes stored mapping for the specified host transport address
|
||||
func (pa *OSAllocator) Deallocate(hostIP net.IP, proto types.Protocol, hostPort int) error {
|
||||
pa.lock.Lock()
|
||||
defer pa.lock.Unlock()
|
||||
|
||||
addr, ok := netip.AddrFromSlice(hostIP)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid HostIP: %s", hostIP)
|
||||
}
|
||||
|
||||
if pm.osListeners[proto] == nil {
|
||||
if pa.osListeners[proto] == nil {
|
||||
return ErrPortNotMapped
|
||||
}
|
||||
|
||||
hAddrPort := netip.AddrPortFrom(addr, uint16(hostPort))
|
||||
osListener, exists := pm.osListeners[proto][hAddrPort]
|
||||
osListener, exists := pa.osListeners[proto][hAddrPort]
|
||||
if !exists {
|
||||
return ErrPortNotMapped
|
||||
}
|
||||
@@ -147,8 +146,8 @@ func (pm *PortMapper) Unmap(hostIP net.IP, proto types.Protocol, hostPort int) e
|
||||
}
|
||||
}
|
||||
|
||||
delete(pm.osListeners[proto], hAddrPort)
|
||||
delete(pa.osListeners[proto], hAddrPort)
|
||||
|
||||
pm.allocator.ReleasePort(hostIP, proto.String(), int(hostPort))
|
||||
pa.allocator.ReleasePort(hostIP, proto.String(), int(hostPort))
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user