github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/mergeCode/libnetwork/drivers/solaris/bridge/port_mapping.go (about) 1 // +build solaris 2 3 package bridge 4 5 import ( 6 "bytes" 7 "errors" 8 "fmt" 9 "net" 10 "os" 11 "os/exec" 12 13 "github.com/Sirupsen/logrus" 14 "github.com/docker/libnetwork/types" 15 ) 16 17 var ( 18 defaultBindingIP = net.IPv4(0, 0, 0, 0) 19 ) 20 21 const ( 22 maxAllocatePortAttempts = 10 23 ) 24 25 func addPFRules(epid, bindIntf string, bs []types.PortBinding) { 26 var id string 27 28 if len(epid) > 12 { 29 id = epid[:12] 30 } else { 31 id = epid 32 } 33 34 fname := "/var/lib/docker/network/files/pf." + id 35 36 f, err := os.OpenFile(fname, 37 os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600) 38 if err != nil { 39 logrus.Warnf("cannot open temp pf file") 40 return 41 } 42 for _, b := range bs { 43 r := fmt.Sprintf( 44 "pass in on %s proto %s from any to (%s) "+ 45 "port %d rdr-to %s port %d\n", bindIntf, 46 b.Proto.String(), bindIntf, b.HostPort, 47 b.IP.String(), b.Port) 48 _, err = f.WriteString(r) 49 if err != nil { 50 logrus.Warnf("cannot write firewall rules to %s: %v", fname, err) 51 } 52 } 53 f.Close() 54 55 anchor := fmt.Sprintf("_auto/docker/ep%s", id) 56 err = exec.Command("/usr/sbin/pfctl", "-a", anchor, "-f", fname).Run() 57 if err != nil { 58 logrus.Warnf("failed to add firewall rules: %v", err) 59 } 60 os.Remove(fname) 61 } 62 63 func removePFRules(epid string) { 64 var id string 65 66 if len(epid) > 12 { 67 id = epid[:12] 68 } else { 69 id = epid 70 } 71 72 anchor := fmt.Sprintf("_auto/docker/ep%s", id) 73 err := exec.Command("/usr/sbin/pfctl", "-a", anchor, "-F", "all").Run() 74 if err != nil { 75 logrus.Warnf("failed to remove firewall rules: %v", err) 76 } 77 } 78 79 func (n *bridgeNetwork) allocatePorts(ep *bridgeEndpoint, bindIntf string, reqDefBindIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) { 80 if ep.extConnConfig == nil || ep.extConnConfig.PortBindings == nil { 81 return nil, nil 82 } 83 84 defHostIP := defaultBindingIP 85 if reqDefBindIP != nil { 86 defHostIP = reqDefBindIP 87 } 88 89 bs, err := n.allocatePortsInternal(ep.extConnConfig.PortBindings, bindIntf, ep.addr.IP, defHostIP, ulPxyEnabled) 90 if err != nil { 91 return nil, err 92 } 93 94 // Add PF rules for port bindings, if any 95 if len(bs) > 0 { 96 addPFRules(ep.id, bindIntf, bs) 97 } 98 99 return bs, err 100 } 101 102 func (n *bridgeNetwork) allocatePortsInternal(bindings []types.PortBinding, bindIntf string, containerIP, defHostIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) { 103 bs := make([]types.PortBinding, 0, len(bindings)) 104 for _, c := range bindings { 105 b := c.GetCopy() 106 if err := n.allocatePort(&b, containerIP, defHostIP); err != nil { 107 // On allocation failure,release previously 108 // allocated ports. On cleanup error, just log 109 // a warning message 110 if cuErr := n.releasePortsInternal(bs); cuErr != nil { 111 logrus.Warnf("Upon allocation failure "+ 112 "for %v, failed to clear previously "+ 113 "allocated port bindings: %v", b, cuErr) 114 } 115 return nil, err 116 } 117 bs = append(bs, b) 118 } 119 return bs, nil 120 } 121 122 func (n *bridgeNetwork) allocatePort(bnd *types.PortBinding, containerIP, defHostIP net.IP) error { 123 var ( 124 host net.Addr 125 err error 126 ) 127 128 // Store the container interface address in the operational binding 129 bnd.IP = containerIP 130 131 // Adjust the host address in the operational binding 132 if len(bnd.HostIP) == 0 { 133 bnd.HostIP = defHostIP 134 } 135 136 // Adjust HostPortEnd if this is not a range. 137 if bnd.HostPortEnd == 0 { 138 bnd.HostPortEnd = bnd.HostPort 139 } 140 141 // Construct the container side transport address 142 container, err := bnd.ContainerAddr() 143 if err != nil { 144 return err 145 } 146 147 // Try up to maxAllocatePortAttempts times to get a port that's 148 // not already allocated. 149 for i := 0; i < maxAllocatePortAttempts; i++ { 150 if host, err = n.portMapper.MapRange(container, bnd.HostIP, 151 int(bnd.HostPort), int(bnd.HostPortEnd), false); err == nil { 152 break 153 } 154 // There is no point in immediately retrying to map an 155 // explicitly chosen port. 156 if bnd.HostPort != 0 { 157 logrus.Warnf( 158 "Failed to allocate and map port %d-%d: %s", 159 bnd.HostPort, bnd.HostPortEnd, err) 160 break 161 } 162 logrus.Warnf("Failed to allocate and map port: %s, retry: %d", 163 err, i+1) 164 } 165 if err != nil { 166 return err 167 } 168 169 // Save the host port (regardless it was or not specified in the 170 // binding) 171 switch netAddr := host.(type) { 172 case *net.TCPAddr: 173 bnd.HostPort = uint16(host.(*net.TCPAddr).Port) 174 return nil 175 case *net.UDPAddr: 176 bnd.HostPort = uint16(host.(*net.UDPAddr).Port) 177 return nil 178 default: 179 // For completeness 180 return ErrUnsupportedAddressType(fmt.Sprintf("%T", netAddr)) 181 } 182 } 183 184 func (n *bridgeNetwork) releasePorts(ep *bridgeEndpoint) error { 185 err := n.releasePortsInternal(ep.portMapping) 186 if err != nil { 187 return nil 188 } 189 190 // remove rules if there are any port mappings 191 if len(ep.portMapping) > 0 { 192 removePFRules(ep.id) 193 } 194 195 return nil 196 197 } 198 199 func (n *bridgeNetwork) releasePortsInternal(bindings []types.PortBinding) error { 200 var errorBuf bytes.Buffer 201 202 // Attempt to release all port bindings, do not stop on failure 203 for _, m := range bindings { 204 if err := n.releasePort(m); err != nil { 205 errorBuf.WriteString( 206 fmt.Sprintf( 207 "\ncould not release %v because of %v", 208 m, err)) 209 } 210 } 211 212 if errorBuf.Len() != 0 { 213 return errors.New(errorBuf.String()) 214 } 215 return nil 216 } 217 218 func (n *bridgeNetwork) releasePort(bnd types.PortBinding) error { 219 // Construct the host side transport address 220 host, err := bnd.HostAddr() 221 if err != nil { 222 return err 223 } 224 return n.portMapper.Unmap(host) 225 }