github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/mergeCode/libnetwork/drivers/bridge/port_mapping.go (about)

     1  package bridge
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"net"
     8  
     9  	"github.com/Sirupsen/logrus"
    10  	"github.com/docker/libnetwork/types"
    11  )
    12  
    13  var (
    14  	defaultBindingIP = net.IPv4(0, 0, 0, 0)
    15  )
    16  
    17  func (n *bridgeNetwork) allocatePorts(ep *bridgeEndpoint, reqDefBindIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
    18  	if ep.extConnConfig == nil || ep.extConnConfig.PortBindings == nil {
    19  		return nil, nil
    20  	}
    21  
    22  	defHostIP := defaultBindingIP
    23  	if reqDefBindIP != nil {
    24  		defHostIP = reqDefBindIP
    25  	}
    26  
    27  	return n.allocatePortsInternal(ep.extConnConfig.PortBindings, ep.addr.IP, defHostIP, ulPxyEnabled)
    28  }
    29  
    30  func (n *bridgeNetwork) allocatePortsInternal(bindings []types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
    31  	bs := make([]types.PortBinding, 0, len(bindings))
    32  	for _, c := range bindings {
    33  		b := c.GetCopy()
    34  		if err := n.allocatePort(&b, containerIP, defHostIP, ulPxyEnabled); err != nil {
    35  			// On allocation failure, release previously allocated ports. On cleanup error, just log a warning message
    36  			if cuErr := n.releasePortsInternal(bs); cuErr != nil {
    37  				logrus.Warnf("Upon allocation failure for %v, failed to clear previously allocated port bindings: %v", b, cuErr)
    38  			}
    39  			return nil, err
    40  		}
    41  		bs = append(bs, b)
    42  	}
    43  	return bs, nil
    44  }
    45  
    46  func (n *bridgeNetwork) allocatePort(bnd *types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) error {
    47  	var (
    48  		host net.Addr
    49  		err  error
    50  	)
    51  
    52  	// Store the container interface address in the operational binding
    53  	bnd.IP = containerIP
    54  
    55  	// Adjust the host address in the operational binding
    56  	if len(bnd.HostIP) == 0 {
    57  		bnd.HostIP = defHostIP
    58  	}
    59  
    60  	// Adjust HostPortEnd if this is not a range.
    61  	if bnd.HostPortEnd == 0 {
    62  		bnd.HostPortEnd = bnd.HostPort
    63  	}
    64  
    65  	// Construct the container side transport address
    66  	container, err := bnd.ContainerAddr()
    67  	if err != nil {
    68  		return err
    69  	}
    70  
    71  	// Try up to maxAllocatePortAttempts times to get a port that's not already allocated.
    72  	for i := 0; i < maxAllocatePortAttempts; i++ {
    73  		if host, err = n.portMapper.MapRange(container, bnd.HostIP, int(bnd.HostPort), int(bnd.HostPortEnd), ulPxyEnabled); err == nil {
    74  			break
    75  		}
    76  		// There is no point in immediately retrying to map an explicitly chosen port.
    77  		if bnd.HostPort != 0 {
    78  			logrus.Warnf("Failed to allocate and map port %d-%d: %s", bnd.HostPort, bnd.HostPortEnd, err)
    79  			break
    80  		}
    81  		logrus.Warnf("Failed to allocate and map port: %s, retry: %d", err, i+1)
    82  	}
    83  	if err != nil {
    84  		return err
    85  	}
    86  
    87  	// Save the host port (regardless it was or not specified in the binding)
    88  	switch netAddr := host.(type) {
    89  	case *net.TCPAddr:
    90  		bnd.HostPort = uint16(host.(*net.TCPAddr).Port)
    91  		return nil
    92  	case *net.UDPAddr:
    93  		bnd.HostPort = uint16(host.(*net.UDPAddr).Port)
    94  		return nil
    95  	default:
    96  		// For completeness
    97  		return ErrUnsupportedAddressType(fmt.Sprintf("%T", netAddr))
    98  	}
    99  }
   100  
   101  func (n *bridgeNetwork) releasePorts(ep *bridgeEndpoint) error {
   102  	return n.releasePortsInternal(ep.portMapping)
   103  }
   104  
   105  func (n *bridgeNetwork) releasePortsInternal(bindings []types.PortBinding) error {
   106  	var errorBuf bytes.Buffer
   107  
   108  	// Attempt to release all port bindings, do not stop on failure
   109  	for _, m := range bindings {
   110  		if err := n.releasePort(m); err != nil {
   111  			errorBuf.WriteString(fmt.Sprintf("\ncould not release %v because of %v", m, err))
   112  		}
   113  	}
   114  
   115  	if errorBuf.Len() != 0 {
   116  		return errors.New(errorBuf.String())
   117  	}
   118  	return nil
   119  }
   120  
   121  func (n *bridgeNetwork) releasePort(bnd types.PortBinding) error {
   122  	// Construct the host side transport address
   123  	host, err := bnd.HostAddr()
   124  	if err != nil {
   125  		return err
   126  	}
   127  	return n.portMapper.Unmap(host)
   128  }