github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/libnetwork/drivers/windows/overlay/ov_endpoint_windows.go (about) 1 package overlay 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net" 7 "sync" 8 9 "github.com/Microsoft/hcsshim" 10 "github.com/Microsoft/hcsshim/osversion" 11 "github.com/docker/libnetwork/driverapi" 12 "github.com/docker/libnetwork/drivers/windows" 13 "github.com/docker/libnetwork/netlabel" 14 "github.com/docker/libnetwork/types" 15 "github.com/sirupsen/logrus" 16 ) 17 18 type endpointTable map[string]*endpoint 19 20 const overlayEndpointPrefix = "overlay/endpoint" 21 22 type endpoint struct { 23 id string 24 nid string 25 profileID string 26 remote bool 27 mac net.HardwareAddr 28 addr *net.IPNet 29 disablegateway bool 30 portMapping []types.PortBinding // Operation port bindings 31 } 32 33 var ( 34 //Server 2016 (RS1) does not support concurrent add/delete of endpoints. Therefore, we need 35 //to use this mutex and serialize the add/delete of endpoints on RS1. 36 endpointMu sync.Mutex 37 windowsBuild = osversion.Build() 38 ) 39 40 func validateID(nid, eid string) error { 41 if nid == "" { 42 return fmt.Errorf("invalid network id") 43 } 44 45 if eid == "" { 46 return fmt.Errorf("invalid endpoint id") 47 } 48 49 return nil 50 } 51 52 func (n *network) endpoint(eid string) *endpoint { 53 n.Lock() 54 defer n.Unlock() 55 56 return n.endpoints[eid] 57 } 58 59 func (n *network) addEndpoint(ep *endpoint) { 60 n.Lock() 61 n.endpoints[ep.id] = ep 62 n.Unlock() 63 } 64 65 func (n *network) deleteEndpoint(eid string) { 66 n.Lock() 67 delete(n.endpoints, eid) 68 n.Unlock() 69 } 70 71 func (n *network) removeEndpointWithAddress(addr *net.IPNet) { 72 var networkEndpoint *endpoint 73 n.Lock() 74 for _, ep := range n.endpoints { 75 if ep.addr.IP.Equal(addr.IP) { 76 networkEndpoint = ep 77 break 78 } 79 } 80 81 if networkEndpoint != nil { 82 delete(n.endpoints, networkEndpoint.id) 83 } 84 n.Unlock() 85 86 if networkEndpoint != nil { 87 logrus.Debugf("Removing stale endpoint from HNS") 88 _, err := endpointRequest("DELETE", networkEndpoint.profileID, "") 89 if err != nil { 90 logrus.Debugf("Failed to delete stale overlay endpoint (%.7s) from hns", networkEndpoint.id) 91 } 92 } 93 } 94 95 func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, 96 epOptions map[string]interface{}) error { 97 var err error 98 if err = validateID(nid, eid); err != nil { 99 return err 100 } 101 102 n := d.network(nid) 103 if n == nil { 104 return fmt.Errorf("network id %q not found", nid) 105 } 106 107 ep := n.endpoint(eid) 108 if ep != nil { 109 logrus.Debugf("Deleting stale endpoint %s", eid) 110 n.deleteEndpoint(eid) 111 _, err := endpointRequest("DELETE", ep.profileID, "") 112 if err != nil { 113 return err 114 } 115 } 116 117 ep = &endpoint{ 118 id: eid, 119 nid: n.id, 120 addr: ifInfo.Address(), 121 mac: ifInfo.MacAddress(), 122 } 123 124 if ep.addr == nil { 125 return fmt.Errorf("create endpoint was not passed interface IP address") 126 } 127 128 s := n.getSubnetforIP(ep.addr) 129 if s == nil { 130 return fmt.Errorf("no matching subnet for IP %q in network %q", ep.addr, nid) 131 } 132 133 // Todo: Add port bindings and qos policies here 134 135 hnsEndpoint := &hcsshim.HNSEndpoint{ 136 Name: eid, 137 VirtualNetwork: n.hnsID, 138 IPAddress: ep.addr.IP, 139 EnableInternalDNS: true, 140 GatewayAddress: s.gwIP.String(), 141 } 142 143 if ep.mac != nil { 144 hnsEndpoint.MacAddress = ep.mac.String() 145 } 146 147 paPolicy, err := json.Marshal(hcsshim.PaPolicy{ 148 Type: "PA", 149 PA: n.providerAddress, 150 }) 151 152 if err != nil { 153 return err 154 } 155 156 hnsEndpoint.Policies = append(hnsEndpoint.Policies, paPolicy) 157 158 if osversion.Build() > 16236 { 159 natPolicy, err := json.Marshal(hcsshim.PaPolicy{ 160 Type: "OutBoundNAT", 161 }) 162 163 if err != nil { 164 return err 165 } 166 167 hnsEndpoint.Policies = append(hnsEndpoint.Policies, natPolicy) 168 169 epConnectivity, err := windows.ParseEndpointConnectivity(epOptions) 170 if err != nil { 171 return err 172 } 173 174 ep.portMapping = epConnectivity.PortBindings 175 ep.portMapping, err = windows.AllocatePorts(n.portMapper, ep.portMapping, ep.addr.IP) 176 if err != nil { 177 return err 178 } 179 180 defer func() { 181 if err != nil { 182 windows.ReleasePorts(n.portMapper, ep.portMapping) 183 } 184 }() 185 186 pbPolicy, err := windows.ConvertPortBindings(ep.portMapping) 187 if err != nil { 188 return err 189 } 190 hnsEndpoint.Policies = append(hnsEndpoint.Policies, pbPolicy...) 191 192 ep.disablegateway = true 193 } 194 195 configurationb, err := json.Marshal(hnsEndpoint) 196 if err != nil { 197 return err 198 } 199 200 hnsresponse, err := endpointRequest("POST", "", string(configurationb)) 201 if err != nil { 202 return err 203 } 204 205 ep.profileID = hnsresponse.Id 206 207 if ep.mac == nil { 208 ep.mac, err = net.ParseMAC(hnsresponse.MacAddress) 209 if err != nil { 210 return err 211 } 212 213 if err := ifInfo.SetMacAddress(ep.mac); err != nil { 214 return err 215 } 216 } 217 218 ep.portMapping, err = windows.ParsePortBindingPolicies(hnsresponse.Policies) 219 if err != nil { 220 endpointRequest("DELETE", hnsresponse.Id, "") 221 return err 222 } 223 224 n.addEndpoint(ep) 225 226 return nil 227 } 228 229 func (d *driver) DeleteEndpoint(nid, eid string) error { 230 if err := validateID(nid, eid); err != nil { 231 return err 232 } 233 234 n := d.network(nid) 235 if n == nil { 236 return fmt.Errorf("network id %q not found", nid) 237 } 238 239 ep := n.endpoint(eid) 240 if ep == nil { 241 return fmt.Errorf("endpoint id %q not found", eid) 242 } 243 244 windows.ReleasePorts(n.portMapper, ep.portMapping) 245 246 n.deleteEndpoint(eid) 247 248 _, err := endpointRequest("DELETE", ep.profileID, "") 249 if err != nil { 250 return err 251 } 252 253 return nil 254 } 255 256 func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) { 257 if err := validateID(nid, eid); err != nil { 258 return nil, err 259 } 260 261 n := d.network(nid) 262 if n == nil { 263 return nil, fmt.Errorf("network id %q not found", nid) 264 } 265 266 ep := n.endpoint(eid) 267 if ep == nil { 268 return nil, fmt.Errorf("endpoint id %q not found", eid) 269 } 270 271 data := make(map[string]interface{}, 1) 272 data["hnsid"] = ep.profileID 273 data["AllowUnqualifiedDNSQuery"] = true 274 275 if ep.portMapping != nil { 276 // Return a copy of the operational data 277 pmc := make([]types.PortBinding, 0, len(ep.portMapping)) 278 for _, pm := range ep.portMapping { 279 pmc = append(pmc, pm.GetCopy()) 280 } 281 data[netlabel.PortMap] = pmc 282 } 283 284 return data, nil 285 } 286 287 func endpointRequest(method, path, request string) (*hcsshim.HNSEndpoint, error) { 288 if windowsBuild == 14393 { 289 endpointMu.Lock() 290 } 291 hnsresponse, err := hcsshim.HNSEndpointRequest(method, path, request) 292 if windowsBuild == 14393 { 293 endpointMu.Unlock() 294 } 295 return hnsresponse, err 296 }