github.com/adityamillind98/moby@v23.0.0-rc.4+incompatible/libnetwork/service_common.go (about) 1 //go:build linux || windows 2 // +build linux windows 3 4 package libnetwork 5 6 import ( 7 "net" 8 9 "github.com/docker/docker/libnetwork/internal/setmatrix" 10 "github.com/sirupsen/logrus" 11 ) 12 13 const maxSetStringLen = 350 14 15 func (c *controller) addEndpointNameResolution(svcName, svcID, nID, eID, containerName string, vip net.IP, serviceAliases, taskAliases []string, ip net.IP, addService bool, method string) error { 16 n, err := c.NetworkByID(nID) 17 if err != nil { 18 return err 19 } 20 21 logrus.Debugf("addEndpointNameResolution %s %s add_service:%t sAliases:%v tAliases:%v", eID, svcName, addService, serviceAliases, taskAliases) 22 23 // Add container resolution mappings 24 if err := c.addContainerNameResolution(nID, eID, containerName, taskAliases, ip, method); err != nil { 25 return err 26 } 27 28 serviceID := svcID 29 if serviceID == "" { 30 // This is the case of a normal container not part of a service 31 serviceID = eID 32 } 33 34 // Add endpoint IP to special "tasks.svc_name" so that the applications have access to DNS RR. 35 n.(*network).addSvcRecords(eID, "tasks."+svcName, serviceID, ip, nil, false, method) 36 for _, alias := range serviceAliases { 37 n.(*network).addSvcRecords(eID, "tasks."+alias, serviceID, ip, nil, false, method) 38 } 39 40 // Add service name to vip in DNS, if vip is valid. Otherwise resort to DNS RR 41 if len(vip) == 0 { 42 n.(*network).addSvcRecords(eID, svcName, serviceID, ip, nil, false, method) 43 for _, alias := range serviceAliases { 44 n.(*network).addSvcRecords(eID, alias, serviceID, ip, nil, false, method) 45 } 46 } 47 48 if addService && len(vip) != 0 { 49 n.(*network).addSvcRecords(eID, svcName, serviceID, vip, nil, false, method) 50 for _, alias := range serviceAliases { 51 n.(*network).addSvcRecords(eID, alias, serviceID, vip, nil, false, method) 52 } 53 } 54 55 return nil 56 } 57 58 func (c *controller) addContainerNameResolution(nID, eID, containerName string, taskAliases []string, ip net.IP, method string) error { 59 n, err := c.NetworkByID(nID) 60 if err != nil { 61 return err 62 } 63 logrus.Debugf("addContainerNameResolution %s %s", eID, containerName) 64 65 // Add resolution for container name 66 n.(*network).addSvcRecords(eID, containerName, eID, ip, nil, true, method) 67 68 // Add resolution for taskaliases 69 for _, alias := range taskAliases { 70 n.(*network).addSvcRecords(eID, alias, eID, ip, nil, false, method) 71 } 72 73 return nil 74 } 75 76 func (c *controller) deleteEndpointNameResolution(svcName, svcID, nID, eID, containerName string, vip net.IP, serviceAliases, taskAliases []string, ip net.IP, rmService, multipleEntries bool, method string) error { 77 n, err := c.NetworkByID(nID) 78 if err != nil { 79 return err 80 } 81 82 logrus.Debugf("deleteEndpointNameResolution %s %s rm_service:%t suppress:%t sAliases:%v tAliases:%v", eID, svcName, rmService, multipleEntries, serviceAliases, taskAliases) 83 84 // Delete container resolution mappings 85 if err := c.delContainerNameResolution(nID, eID, containerName, taskAliases, ip, method); err != nil { 86 logrus.WithError(err).Warn("Error delting container from resolver") 87 } 88 89 serviceID := svcID 90 if serviceID == "" { 91 // This is the case of a normal container not part of a service 92 serviceID = eID 93 } 94 95 // Delete the special "tasks.svc_name" backend record. 96 if !multipleEntries { 97 n.(*network).deleteSvcRecords(eID, "tasks."+svcName, serviceID, ip, nil, false, method) 98 for _, alias := range serviceAliases { 99 n.(*network).deleteSvcRecords(eID, "tasks."+alias, serviceID, ip, nil, false, method) 100 } 101 } 102 103 // If we are doing DNS RR delete the endpoint IP from DNS record right away. 104 if !multipleEntries && len(vip) == 0 { 105 n.(*network).deleteSvcRecords(eID, svcName, serviceID, ip, nil, false, method) 106 for _, alias := range serviceAliases { 107 n.(*network).deleteSvcRecords(eID, alias, serviceID, ip, nil, false, method) 108 } 109 } 110 111 // Remove the DNS record for VIP only if we are removing the service 112 if rmService && len(vip) != 0 && !multipleEntries { 113 n.(*network).deleteSvcRecords(eID, svcName, serviceID, vip, nil, false, method) 114 for _, alias := range serviceAliases { 115 n.(*network).deleteSvcRecords(eID, alias, serviceID, vip, nil, false, method) 116 } 117 } 118 119 return nil 120 } 121 122 func (c *controller) delContainerNameResolution(nID, eID, containerName string, taskAliases []string, ip net.IP, method string) error { 123 n, err := c.NetworkByID(nID) 124 if err != nil { 125 return err 126 } 127 logrus.Debugf("delContainerNameResolution %s %s", eID, containerName) 128 129 // Delete resolution for container name 130 n.(*network).deleteSvcRecords(eID, containerName, eID, ip, nil, true, method) 131 132 // Delete resolution for taskaliases 133 for _, alias := range taskAliases { 134 n.(*network).deleteSvcRecords(eID, alias, eID, ip, nil, true, method) 135 } 136 137 return nil 138 } 139 140 func newService(name string, id string, ingressPorts []*PortConfig, serviceAliases []string) *service { 141 return &service{ 142 name: name, 143 id: id, 144 ingressPorts: ingressPorts, 145 loadBalancers: make(map[string]*loadBalancer), 146 aliases: serviceAliases, 147 ipToEndpoint: setmatrix.NewSetMatrix(), 148 } 149 } 150 151 func (c *controller) getLBIndex(sid, nid string, ingressPorts []*PortConfig) int { 152 skey := serviceKey{ 153 id: sid, 154 ports: portConfigs(ingressPorts).String(), 155 } 156 c.Lock() 157 s, ok := c.serviceBindings[skey] 158 c.Unlock() 159 160 if !ok { 161 return 0 162 } 163 164 s.Lock() 165 lb := s.loadBalancers[nid] 166 s.Unlock() 167 168 return int(lb.fwMark) 169 } 170 171 // cleanupServiceDiscovery when the network is being deleted, erase all the associated service discovery records 172 func (c *controller) cleanupServiceDiscovery(cleanupNID string) { 173 c.Lock() 174 defer c.Unlock() 175 if cleanupNID == "" { 176 logrus.Debugf("cleanupServiceDiscovery for all networks") 177 c.svcRecords = make(map[string]svcInfo) 178 return 179 } 180 logrus.Debugf("cleanupServiceDiscovery for network:%s", cleanupNID) 181 delete(c.svcRecords, cleanupNID) 182 } 183 184 func (c *controller) cleanupServiceBindings(cleanupNID string) { 185 var cleanupFuncs []func() 186 187 logrus.Debugf("cleanupServiceBindings for %s", cleanupNID) 188 c.Lock() 189 services := make([]*service, 0, len(c.serviceBindings)) 190 for _, s := range c.serviceBindings { 191 services = append(services, s) 192 } 193 c.Unlock() 194 195 for _, s := range services { 196 s.Lock() 197 // Skip the serviceBindings that got deleted 198 if s.deleted { 199 s.Unlock() 200 continue 201 } 202 for nid, lb := range s.loadBalancers { 203 if cleanupNID != "" && nid != cleanupNID { 204 continue 205 } 206 for eid, be := range lb.backEnds { 207 cleanupFuncs = append(cleanupFuncs, makeServiceCleanupFunc(c, s, nid, eid, lb.vip, be.ip)) 208 } 209 } 210 s.Unlock() 211 } 212 213 for _, f := range cleanupFuncs { 214 f() 215 } 216 } 217 218 func makeServiceCleanupFunc(c *controller, s *service, nID, eID string, vip net.IP, ip net.IP) func() { 219 // ContainerName and taskAliases are not available here, this is still fine because the Service discovery 220 // cleanup already happened before. The only thing that rmServiceBinding is still doing here a part from the Load 221 // Balancer bookeeping, is to keep consistent the mapping of endpoint to IP. 222 return func() { 223 if err := c.rmServiceBinding(s.name, s.id, nID, eID, "", vip, s.ingressPorts, s.aliases, []string{}, ip, "cleanupServiceBindings", false, true); err != nil { 224 logrus.Errorf("Failed to remove service bindings for service %s network %s endpoint %s while cleanup: %v", s.id, nID, eID, err) 225 } 226 } 227 } 228 229 func (c *controller) addServiceBinding(svcName, svcID, nID, eID, containerName string, vip net.IP, ingressPorts []*PortConfig, serviceAliases, taskAliases []string, ip net.IP, method string) error { 230 var addService bool 231 232 // Failure to lock the network ID on add can result in racing 233 // racing against network deletion resulting in inconsistent 234 // state in the c.serviceBindings map and it's sub-maps. Also, 235 // always lock network ID before services to avoid deadlock. 236 c.networkLocker.Lock(nID) 237 defer c.networkLocker.Unlock(nID) //nolint:errcheck 238 239 n, err := c.NetworkByID(nID) 240 if err != nil { 241 return err 242 } 243 244 skey := serviceKey{ 245 id: svcID, 246 ports: portConfigs(ingressPorts).String(), 247 } 248 249 var s *service 250 for { 251 c.Lock() 252 var ok bool 253 s, ok = c.serviceBindings[skey] 254 if !ok { 255 // Create a new service if we are seeing this service 256 // for the first time. 257 s = newService(svcName, svcID, ingressPorts, serviceAliases) 258 c.serviceBindings[skey] = s 259 } 260 c.Unlock() 261 s.Lock() 262 if !s.deleted { 263 // ok the object is good to be used 264 break 265 } 266 s.Unlock() 267 } 268 logrus.Debugf("addServiceBinding from %s START for %s %s p:%p nid:%s skey:%v", method, svcName, eID, s, nID, skey) 269 defer s.Unlock() 270 271 lb, ok := s.loadBalancers[nID] 272 if !ok { 273 // Create a new load balancer if we are seeing this 274 // network attachment on the service for the first 275 // time. 276 fwMarkCtrMu.Lock() 277 278 lb = &loadBalancer{ 279 vip: vip, 280 fwMark: fwMarkCtr, 281 backEnds: make(map[string]*lbBackend), 282 service: s, 283 } 284 285 fwMarkCtr++ 286 fwMarkCtrMu.Unlock() 287 288 s.loadBalancers[nID] = lb 289 addService = true 290 } 291 292 lb.backEnds[eID] = &lbBackend{ip, false} 293 294 ok, entries := s.assignIPToEndpoint(ip.String(), eID) 295 if !ok || entries > 1 { 296 setStr, b := s.printIPToEndpoint(ip.String()) 297 if len(setStr) > maxSetStringLen { 298 setStr = setStr[:maxSetStringLen] 299 } 300 logrus.Warnf("addServiceBinding %s possible transient state ok:%t entries:%d set:%t %s", eID, ok, entries, b, setStr) 301 } 302 303 // Add loadbalancer service and backend to the network 304 n.(*network).addLBBackend(ip, lb) 305 306 // Add the appropriate name resolutions 307 if err := c.addEndpointNameResolution(svcName, svcID, nID, eID, containerName, vip, serviceAliases, taskAliases, ip, addService, "addServiceBinding"); err != nil { 308 return err 309 } 310 311 logrus.Debugf("addServiceBinding from %s END for %s %s", method, svcName, eID) 312 313 return nil 314 } 315 316 func (c *controller) rmServiceBinding(svcName, svcID, nID, eID, containerName string, vip net.IP, ingressPorts []*PortConfig, serviceAliases []string, taskAliases []string, ip net.IP, method string, deleteSvcRecords bool, fullRemove bool) error { 317 var rmService bool 318 319 skey := serviceKey{ 320 id: svcID, 321 ports: portConfigs(ingressPorts).String(), 322 } 323 324 c.Lock() 325 s, ok := c.serviceBindings[skey] 326 c.Unlock() 327 if !ok { 328 logrus.Warnf("rmServiceBinding %s %s %s aborted c.serviceBindings[skey] !ok", method, svcName, eID) 329 return nil 330 } 331 332 s.Lock() 333 defer s.Unlock() 334 logrus.Debugf("rmServiceBinding from %s START for %s %s p:%p nid:%s sKey:%v deleteSvc:%t", method, svcName, eID, s, nID, skey, deleteSvcRecords) 335 lb, ok := s.loadBalancers[nID] 336 if !ok { 337 logrus.Warnf("rmServiceBinding %s %s %s aborted s.loadBalancers[nid] !ok", method, svcName, eID) 338 return nil 339 } 340 341 be, ok := lb.backEnds[eID] 342 if !ok { 343 logrus.Warnf("rmServiceBinding %s %s %s aborted lb.backEnds[eid] && lb.disabled[eid] !ok", method, svcName, eID) 344 return nil 345 } 346 347 if fullRemove { 348 // delete regardless 349 delete(lb.backEnds, eID) 350 } else { 351 be.disabled = true 352 } 353 354 if len(lb.backEnds) == 0 { 355 // All the backends for this service have been 356 // removed. Time to remove the load balancer and also 357 // remove the service entry in IPVS. 358 rmService = true 359 360 delete(s.loadBalancers, nID) 361 logrus.Debugf("rmServiceBinding %s delete %s, p:%p in loadbalancers len:%d", eID, nID, lb, len(s.loadBalancers)) 362 } 363 364 ok, entries := s.removeIPToEndpoint(ip.String(), eID) 365 if !ok || entries > 0 { 366 setStr, b := s.printIPToEndpoint(ip.String()) 367 if len(setStr) > maxSetStringLen { 368 setStr = setStr[:maxSetStringLen] 369 } 370 logrus.Warnf("rmServiceBinding %s possible transient state ok:%t entries:%d set:%t %s", eID, ok, entries, b, setStr) 371 } 372 373 // Remove loadbalancer service(if needed) and backend in all 374 // sandboxes in the network only if the vip is valid. 375 if entries == 0 { 376 // The network may well have been deleted from the store (and 377 // dataplane) before the last of the service bindings. On Linux that's 378 // ok because removing the network sandbox from the dataplane 379 // implicitly cleans up all related dataplane state. 380 // On the Windows dataplane, VFP policylists must be removed 381 // independently of the network, and they must be removed before the HNS 382 // network. Otherwise, policylist removal fails with "network not 383 // found." On Windows cleanupServiceBindings must be called prior to 384 // removing the network from the store or dataplane. 385 n, err := c.NetworkByID(nID) 386 if err == nil { 387 n.(*network).rmLBBackend(ip, lb, rmService, fullRemove) 388 } 389 } 390 391 // Delete the name resolutions 392 if deleteSvcRecords { 393 if err := c.deleteEndpointNameResolution(svcName, svcID, nID, eID, containerName, vip, serviceAliases, taskAliases, ip, rmService, entries > 0, "rmServiceBinding"); err != nil { 394 return err 395 } 396 } 397 398 if len(s.loadBalancers) == 0 { 399 // All loadbalancers for the service removed. Time to 400 // remove the service itself. 401 c.Lock() 402 403 // Mark the object as deleted so that the add won't use it wrongly 404 s.deleted = true 405 // NOTE The delete from the serviceBindings map has to be the last operation else we are allowing a race between this service 406 // that is getting deleted and a new service that will be created if the entry is not anymore there 407 delete(c.serviceBindings, skey) 408 c.Unlock() 409 } 410 411 logrus.Debugf("rmServiceBinding from %s END for %s %s", method, svcName, eID) 412 return nil 413 }