func (n *bridgeNetwork) allocatePort(bnd *types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) error { var ( host net.Addr err error ) // Store the container interface address in the operational binding bnd.IP = containerIP // Adjust the host address in the operational binding if len(bnd.HostIP) == 0 { bnd.HostIP = defHostIP } // Adjust HostPortEnd if this is not a range. if bnd.HostPortEnd == 0 { bnd.HostPortEnd = bnd.HostPort } // Construct the container side transport address container, err := bnd.ContainerAddr() if err != nil { return err } // Try up to maxAllocatePortAttempts times to get a port that's not already allocated. for i := 0; i < maxAllocatePortAttempts; i++ { if host, err = n.portMapper.MapRange(container, bnd.HostIP, int(bnd.HostPort), int(bnd.HostPortEnd), ulPxyEnabled); err == nil { break } // There is no point in immediately retrying to map an explicitly chosen port. if bnd.HostPort != 0 { logrus.Warnf("Failed to allocate and map port %d-%d: %s", bnd.HostPort, bnd.HostPortEnd, err) break } logrus.Warnf("Failed to allocate and map port: %s, retry: %d", err, i+1) } if err != nil { return err } // Save the host port (regardless it was or not specified in the binding) switch netAddr := host.(type) { case *net.TCPAddr: bnd.HostPort = uint16(host.(*net.TCPAddr).Port) return nil case *net.UDPAddr: bnd.HostPort = uint16(host.(*net.UDPAddr).Port) return nil default: // For completeness return ErrUnsupportedAddressType(fmt.Sprintf("%T", netAddr)) } }