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 }