github.com/tonistiigi/docker@v0.10.1-0.20240229224939-974013b0dc6a/libnetwork/endpoint.go (about) 1 // FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16: 2 //go:build go1.19 3 4 package libnetwork 5 6 import ( 7 "context" 8 "encoding/json" 9 "fmt" 10 "net" 11 "sync" 12 13 "github.com/containerd/log" 14 "github.com/docker/docker/internal/sliceutil" 15 "github.com/docker/docker/libnetwork/datastore" 16 "github.com/docker/docker/libnetwork/ipamapi" 17 "github.com/docker/docker/libnetwork/netlabel" 18 "github.com/docker/docker/libnetwork/options" 19 "github.com/docker/docker/libnetwork/scope" 20 "github.com/docker/docker/libnetwork/types" 21 ) 22 23 // ByNetworkType sorts a [Endpoint] slice based on the network-type 24 // they're attached to. It implements [sort.Interface] and can be used 25 // with [sort.Stable] or [sort.Sort]. It is used by [Sandbox.ResolveName] 26 // when resolving names in swarm mode. In swarm mode, services with exposed 27 // ports are connected to user overlay network, ingress network, and local 28 // ("docker_gwbridge") networks. Name resolution should prioritize returning 29 // the VIP/IPs on user overlay network over ingress and local networks. 30 // 31 // ByNetworkType re-orders the endpoints based on the network-type they 32 // are attached to: 33 // 34 // 1. dynamic networks (user overlay networks) 35 // 2. ingress network(s) 36 // 3. local networks ("docker_gwbridge") 37 type ByNetworkType []*Endpoint 38 39 func (ep ByNetworkType) Len() int { return len(ep) } 40 func (ep ByNetworkType) Swap(i, j int) { ep[i], ep[j] = ep[j], ep[i] } 41 func (ep ByNetworkType) Less(i, j int) bool { 42 return getNetworkType(ep[i].getNetwork()) < getNetworkType(ep[j].getNetwork()) 43 } 44 45 // Define the order in which resolution should happen if an endpoint is 46 // attached to multiple network-types. It is used by [ByNetworkType]. 47 const ( 48 typeDynamic = iota 49 typeIngress 50 typeLocal 51 ) 52 53 func getNetworkType(nw *Network) int { 54 switch { 55 case nw.ingress: 56 return typeIngress 57 case nw.dynamic: 58 return typeDynamic 59 default: 60 return typeLocal 61 } 62 } 63 64 // EndpointOption is an option setter function type used to pass various options to Network 65 // and Endpoint interfaces methods. The various setter functions of type EndpointOption are 66 // provided by libnetwork, they look like <Create|Join|Leave>Option[...](...) 67 type EndpointOption func(ep *Endpoint) 68 69 // Endpoint represents a logical connection between a network and a sandbox. 70 type Endpoint struct { 71 name string 72 id string 73 network *Network 74 iface *EndpointInterface 75 joinInfo *endpointJoinInfo 76 sandboxID string 77 exposedPorts []types.TransportPort 78 // dnsNames holds all the non-fully qualified DNS names associated to this endpoint. Order matters: first entry 79 // will be used for the PTR records associated to the endpoint's IPv4 and IPv6 addresses. 80 dnsNames []string 81 disableResolution bool 82 generic map[string]interface{} 83 prefAddress net.IP 84 prefAddressV6 net.IP 85 ipamOptions map[string]string 86 aliases map[string]string 87 svcID string 88 svcName string 89 virtualIP net.IP 90 svcAliases []string 91 ingressPorts []*PortConfig 92 dbIndex uint64 93 dbExists bool 94 serviceEnabled bool 95 loadBalancer bool 96 mu sync.Mutex 97 } 98 99 func (ep *Endpoint) MarshalJSON() ([]byte, error) { 100 ep.mu.Lock() 101 defer ep.mu.Unlock() 102 103 epMap := make(map[string]interface{}) 104 epMap["name"] = ep.name 105 epMap["id"] = ep.id 106 epMap["ep_iface"] = ep.iface 107 epMap["joinInfo"] = ep.joinInfo 108 epMap["exposed_ports"] = ep.exposedPorts 109 if ep.generic != nil { 110 epMap["generic"] = ep.generic 111 } 112 epMap["sandbox"] = ep.sandboxID 113 epMap["dnsNames"] = ep.dnsNames 114 epMap["disableResolution"] = ep.disableResolution 115 epMap["svcName"] = ep.svcName 116 epMap["svcID"] = ep.svcID 117 epMap["virtualIP"] = ep.virtualIP.String() 118 epMap["ingressPorts"] = ep.ingressPorts 119 epMap["svcAliases"] = ep.svcAliases 120 epMap["loadBalancer"] = ep.loadBalancer 121 122 return json.Marshal(epMap) 123 } 124 125 func (ep *Endpoint) UnmarshalJSON(b []byte) (err error) { 126 ep.mu.Lock() 127 defer ep.mu.Unlock() 128 129 var epMap map[string]interface{} 130 if err := json.Unmarshal(b, &epMap); err != nil { 131 return err 132 } 133 ep.name = epMap["name"].(string) 134 ep.id = epMap["id"].(string) 135 136 // TODO(cpuguy83): So yeah, this isn't checking any errors anywhere. 137 // Seems like we should be checking errors even because of memory related issues that can arise. 138 // Alas it seems like given the nature of this data we could introduce problems if we start checking these errors. 139 // 140 // If anyone ever comes here and figures out one way or another if we can/should be checking these errors and it turns out we can't... then please document *why* 141 142 ib, _ := json.Marshal(epMap["ep_iface"]) 143 json.Unmarshal(ib, &ep.iface) //nolint:errcheck 144 145 jb, _ := json.Marshal(epMap["joinInfo"]) 146 json.Unmarshal(jb, &ep.joinInfo) //nolint:errcheck 147 148 tb, _ := json.Marshal(epMap["exposed_ports"]) 149 var tPorts []types.TransportPort 150 json.Unmarshal(tb, &tPorts) //nolint:errcheck 151 ep.exposedPorts = tPorts 152 153 cb, _ := json.Marshal(epMap["sandbox"]) 154 json.Unmarshal(cb, &ep.sandboxID) //nolint:errcheck 155 156 if v, ok := epMap["generic"]; ok { 157 ep.generic = v.(map[string]interface{}) 158 159 if opt, ok := ep.generic[netlabel.PortMap]; ok { 160 pblist := []types.PortBinding{} 161 162 for i := 0; i < len(opt.([]interface{})); i++ { 163 pb := types.PortBinding{} 164 tmp := opt.([]interface{})[i].(map[string]interface{}) 165 166 bytes, err := json.Marshal(tmp) 167 if err != nil { 168 log.G(context.TODO()).Error(err) 169 break 170 } 171 err = json.Unmarshal(bytes, &pb) 172 if err != nil { 173 log.G(context.TODO()).Error(err) 174 break 175 } 176 pblist = append(pblist, pb) 177 } 178 ep.generic[netlabel.PortMap] = pblist 179 } 180 181 if opt, ok := ep.generic[netlabel.ExposedPorts]; ok { 182 tplist := []types.TransportPort{} 183 184 for i := 0; i < len(opt.([]interface{})); i++ { 185 tp := types.TransportPort{} 186 tmp := opt.([]interface{})[i].(map[string]interface{}) 187 188 bytes, err := json.Marshal(tmp) 189 if err != nil { 190 log.G(context.TODO()).Error(err) 191 break 192 } 193 err = json.Unmarshal(bytes, &tp) 194 if err != nil { 195 log.G(context.TODO()).Error(err) 196 break 197 } 198 tplist = append(tplist, tp) 199 } 200 ep.generic[netlabel.ExposedPorts] = tplist 201 } 202 } 203 204 var anonymous bool 205 if v, ok := epMap["anonymous"]; ok { 206 anonymous = v.(bool) 207 } 208 if v, ok := epMap["disableResolution"]; ok { 209 ep.disableResolution = v.(bool) 210 } 211 212 if sn, ok := epMap["svcName"]; ok { 213 ep.svcName = sn.(string) 214 } 215 216 if si, ok := epMap["svcID"]; ok { 217 ep.svcID = si.(string) 218 } 219 220 if vip, ok := epMap["virtualIP"]; ok { 221 ep.virtualIP = net.ParseIP(vip.(string)) 222 } 223 224 if v, ok := epMap["loadBalancer"]; ok { 225 ep.loadBalancer = v.(bool) 226 } 227 228 sal, _ := json.Marshal(epMap["svcAliases"]) 229 var svcAliases []string 230 json.Unmarshal(sal, &svcAliases) //nolint:errcheck 231 ep.svcAliases = svcAliases 232 233 pc, _ := json.Marshal(epMap["ingressPorts"]) 234 var ingressPorts []*PortConfig 235 json.Unmarshal(pc, &ingressPorts) //nolint:errcheck 236 ep.ingressPorts = ingressPorts 237 238 ma, _ := json.Marshal(epMap["myAliases"]) 239 var myAliases []string 240 json.Unmarshal(ma, &myAliases) //nolint:errcheck 241 242 _, hasDNSNames := epMap["dnsNames"] 243 dn, _ := json.Marshal(epMap["dnsNames"]) 244 var dnsNames []string 245 json.Unmarshal(dn, &dnsNames) 246 ep.dnsNames = dnsNames 247 248 // TODO(aker): remove this migration code in v27 249 if !hasDNSNames { 250 // The field dnsNames was introduced in v25.0. If we don't have it, the on-disk state was written by an older 251 // daemon, thus we need to populate dnsNames based off of myAliases and anonymous values. 252 if !anonymous { 253 myAliases = append([]string{ep.name}, myAliases...) 254 } 255 ep.dnsNames = sliceutil.Dedup(myAliases) 256 } 257 258 return nil 259 } 260 261 func (ep *Endpoint) New() datastore.KVObject { 262 return &Endpoint{network: ep.getNetwork()} 263 } 264 265 func (ep *Endpoint) CopyTo(o datastore.KVObject) error { 266 ep.mu.Lock() 267 defer ep.mu.Unlock() 268 269 dstEp := o.(*Endpoint) 270 dstEp.name = ep.name 271 dstEp.id = ep.id 272 dstEp.sandboxID = ep.sandboxID 273 dstEp.dbIndex = ep.dbIndex 274 dstEp.dbExists = ep.dbExists 275 dstEp.disableResolution = ep.disableResolution 276 dstEp.svcName = ep.svcName 277 dstEp.svcID = ep.svcID 278 dstEp.virtualIP = ep.virtualIP 279 dstEp.loadBalancer = ep.loadBalancer 280 281 dstEp.svcAliases = make([]string, len(ep.svcAliases)) 282 copy(dstEp.svcAliases, ep.svcAliases) 283 284 dstEp.ingressPorts = make([]*PortConfig, len(ep.ingressPorts)) 285 copy(dstEp.ingressPorts, ep.ingressPorts) 286 287 if ep.iface != nil { 288 dstEp.iface = &EndpointInterface{} 289 if err := ep.iface.CopyTo(dstEp.iface); err != nil { 290 return err 291 } 292 } 293 294 if ep.joinInfo != nil { 295 dstEp.joinInfo = &endpointJoinInfo{} 296 if err := ep.joinInfo.CopyTo(dstEp.joinInfo); err != nil { 297 return err 298 } 299 } 300 301 dstEp.exposedPorts = make([]types.TransportPort, len(ep.exposedPorts)) 302 copy(dstEp.exposedPorts, ep.exposedPorts) 303 304 dstEp.dnsNames = make([]string, len(ep.dnsNames)) 305 copy(dstEp.dnsNames, ep.dnsNames) 306 307 dstEp.generic = options.Generic{} 308 for k, v := range ep.generic { 309 dstEp.generic[k] = v 310 } 311 312 return nil 313 } 314 315 // ID returns the system-generated id for this endpoint. 316 func (ep *Endpoint) ID() string { 317 ep.mu.Lock() 318 defer ep.mu.Unlock() 319 320 return ep.id 321 } 322 323 // Name returns the name of this endpoint. 324 func (ep *Endpoint) Name() string { 325 ep.mu.Lock() 326 defer ep.mu.Unlock() 327 328 return ep.name 329 } 330 331 // Network returns the name of the network to which this endpoint is attached. 332 func (ep *Endpoint) Network() string { 333 if ep.network == nil { 334 return "" 335 } 336 337 return ep.network.name 338 } 339 340 // getDNSNames returns a copy of the DNS names associated to this endpoint. The first entry is the one used for PTR 341 // records. 342 func (ep *Endpoint) getDNSNames() []string { 343 ep.mu.Lock() 344 defer ep.mu.Unlock() 345 346 dnsNames := make([]string, len(ep.dnsNames)) 347 copy(dnsNames, ep.dnsNames) 348 return dnsNames 349 } 350 351 // isServiceEnabled check if service is enabled on the endpoint 352 func (ep *Endpoint) isServiceEnabled() bool { 353 ep.mu.Lock() 354 defer ep.mu.Unlock() 355 return ep.serviceEnabled 356 } 357 358 // enableService sets service enabled on the endpoint 359 func (ep *Endpoint) enableService() { 360 ep.mu.Lock() 361 defer ep.mu.Unlock() 362 ep.serviceEnabled = true 363 } 364 365 // disableService disables service on the endpoint 366 func (ep *Endpoint) disableService() { 367 ep.mu.Lock() 368 defer ep.mu.Unlock() 369 ep.serviceEnabled = false 370 } 371 372 func (ep *Endpoint) needResolver() bool { 373 ep.mu.Lock() 374 defer ep.mu.Unlock() 375 return !ep.disableResolution 376 } 377 378 // endpoint Key structure : endpoint/network-id/endpoint-id 379 func (ep *Endpoint) Key() []string { 380 if ep.network == nil { 381 return nil 382 } 383 384 return []string{datastore.EndpointKeyPrefix, ep.network.id, ep.id} 385 } 386 387 func (ep *Endpoint) KeyPrefix() []string { 388 if ep.network == nil { 389 return nil 390 } 391 392 return []string{datastore.EndpointKeyPrefix, ep.network.id} 393 } 394 395 func (ep *Endpoint) Value() []byte { 396 b, err := json.Marshal(ep) 397 if err != nil { 398 return nil 399 } 400 return b 401 } 402 403 func (ep *Endpoint) SetValue(value []byte) error { 404 return json.Unmarshal(value, ep) 405 } 406 407 func (ep *Endpoint) Index() uint64 { 408 ep.mu.Lock() 409 defer ep.mu.Unlock() 410 return ep.dbIndex 411 } 412 413 func (ep *Endpoint) SetIndex(index uint64) { 414 ep.mu.Lock() 415 defer ep.mu.Unlock() 416 ep.dbIndex = index 417 ep.dbExists = true 418 } 419 420 func (ep *Endpoint) Exists() bool { 421 ep.mu.Lock() 422 defer ep.mu.Unlock() 423 return ep.dbExists 424 } 425 426 func (ep *Endpoint) Skip() bool { 427 return ep.getNetwork().Skip() 428 } 429 430 func (ep *Endpoint) processOptions(options ...EndpointOption) { 431 ep.mu.Lock() 432 defer ep.mu.Unlock() 433 434 for _, opt := range options { 435 if opt != nil { 436 opt(ep) 437 } 438 } 439 } 440 441 func (ep *Endpoint) getNetwork() *Network { 442 ep.mu.Lock() 443 defer ep.mu.Unlock() 444 445 return ep.network 446 } 447 448 func (ep *Endpoint) getNetworkFromStore() (*Network, error) { 449 if ep.network == nil { 450 return nil, fmt.Errorf("invalid network object in endpoint %s", ep.Name()) 451 } 452 453 return ep.network.getController().getNetworkFromStore(ep.network.id) 454 } 455 456 // Join joins the sandbox to the endpoint and populates into the sandbox 457 // the network resources allocated for the endpoint. 458 func (ep *Endpoint) Join(sb *Sandbox, options ...EndpointOption) error { 459 if sb == nil || sb.ID() == "" || sb.Key() == "" { 460 return types.InvalidParameterErrorf("invalid Sandbox passed to endpoint join: %v", sb) 461 } 462 463 sb.joinLeaveStart() 464 defer sb.joinLeaveEnd() 465 466 return ep.sbJoin(sb, options...) 467 } 468 469 func (ep *Endpoint) sbJoin(sb *Sandbox, options ...EndpointOption) (err error) { 470 n, err := ep.getNetworkFromStore() 471 if err != nil { 472 return fmt.Errorf("failed to get network from store during join: %v", err) 473 } 474 475 ep, err = n.getEndpointFromStore(ep.ID()) 476 if err != nil { 477 return fmt.Errorf("failed to get endpoint from store during join: %v", err) 478 } 479 480 ep.mu.Lock() 481 if ep.sandboxID != "" { 482 ep.mu.Unlock() 483 return types.ForbiddenErrorf("another container is attached to the same network endpoint") 484 } 485 ep.network = n 486 ep.sandboxID = sb.ID() 487 ep.joinInfo = &endpointJoinInfo{} 488 epid := ep.id 489 ep.mu.Unlock() 490 defer func() { 491 if err != nil { 492 ep.mu.Lock() 493 ep.sandboxID = "" 494 ep.mu.Unlock() 495 } 496 }() 497 498 nid := n.ID() 499 500 ep.processOptions(options...) 501 502 d, err := n.driver(true) 503 if err != nil { 504 return fmt.Errorf("failed to get driver during join: %v", err) 505 } 506 507 err = d.Join(nid, epid, sb.Key(), ep, sb.Labels()) 508 if err != nil { 509 return err 510 } 511 defer func() { 512 if err != nil { 513 if e := d.Leave(nid, epid); e != nil { 514 log.G(context.TODO()).Warnf("driver leave failed while rolling back join: %v", e) 515 } 516 } 517 }() 518 519 if !n.getController().isAgent() { 520 if !n.getController().isSwarmNode() || n.Scope() != scope.Swarm || !n.driverIsMultihost() { 521 n.updateSvcRecord(ep, true) 522 } 523 } 524 525 if err := sb.updateHostsFile(ep.getEtcHostsAddrs()); err != nil { 526 return err 527 } 528 if err = sb.updateDNS(n.enableIPv6); err != nil { 529 return err 530 } 531 532 // Current endpoint providing external connectivity for the sandbox 533 extEp := sb.getGatewayEndpoint() 534 535 sb.addEndpoint(ep) 536 defer func() { 537 if err != nil { 538 sb.removeEndpoint(ep) 539 } 540 }() 541 542 if err = sb.populateNetworkResources(ep); err != nil { 543 return err 544 } 545 546 if err = n.getController().updateToStore(ep); err != nil { 547 return err 548 } 549 550 if err = ep.addDriverInfoToCluster(); err != nil { 551 return err 552 } 553 554 defer func() { 555 if err != nil { 556 if e := ep.deleteDriverInfoFromCluster(); e != nil { 557 log.G(context.TODO()).Errorf("Could not delete endpoint state for endpoint %s from cluster on join failure: %v", ep.Name(), e) 558 } 559 } 560 }() 561 562 // Load balancing endpoints should never have a default gateway nor 563 // should they alter the status of a network's default gateway 564 if ep.loadBalancer && !sb.ingress { 565 return nil 566 } 567 568 if sb.needDefaultGW() && sb.getEndpointInGWNetwork() == nil { 569 return sb.setupDefaultGW() 570 } 571 572 moveExtConn := sb.getGatewayEndpoint() != extEp 573 574 if moveExtConn { 575 if extEp != nil { 576 log.G(context.TODO()).Debugf("Revoking external connectivity on endpoint %s (%s)", extEp.Name(), extEp.ID()) 577 extN, err := extEp.getNetworkFromStore() 578 if err != nil { 579 return fmt.Errorf("failed to get network from store for revoking external connectivity during join: %v", err) 580 } 581 extD, err := extN.driver(true) 582 if err != nil { 583 return fmt.Errorf("failed to get driver for revoking external connectivity during join: %v", err) 584 } 585 if err = extD.RevokeExternalConnectivity(extEp.network.ID(), extEp.ID()); err != nil { 586 return types.InternalErrorf( 587 "driver failed revoking external connectivity on endpoint %s (%s): %v", 588 extEp.Name(), extEp.ID(), err) 589 } 590 defer func() { 591 if err != nil { 592 if e := extD.ProgramExternalConnectivity(extEp.network.ID(), extEp.ID(), sb.Labels()); e != nil { 593 log.G(context.TODO()).Warnf("Failed to roll-back external connectivity on endpoint %s (%s): %v", 594 extEp.Name(), extEp.ID(), e) 595 } 596 } 597 }() 598 } 599 if !n.internal { 600 log.G(context.TODO()).Debugf("Programming external connectivity on endpoint %s (%s)", ep.Name(), ep.ID()) 601 if err = d.ProgramExternalConnectivity(n.ID(), ep.ID(), sb.Labels()); err != nil { 602 return types.InternalErrorf( 603 "driver failed programming external connectivity on endpoint %s (%s): %v", 604 ep.Name(), ep.ID(), err) 605 } 606 } 607 } 608 609 if !sb.needDefaultGW() { 610 if e := sb.clearDefaultGW(); e != nil { 611 log.G(context.TODO()).Warnf("Failure while disconnecting sandbox %s (%s) from gateway network: %v", 612 sb.ID(), sb.ContainerID(), e) 613 } 614 } 615 616 return nil 617 } 618 619 func (ep *Endpoint) rename(name string) error { 620 ep.mu.Lock() 621 ep.name = name 622 ep.mu.Unlock() 623 624 // Update the store with the updated name 625 if err := ep.getNetwork().getController().updateToStore(ep); err != nil { 626 return err 627 } 628 629 return nil 630 } 631 632 func (ep *Endpoint) UpdateDNSNames(dnsNames []string) error { 633 nw := ep.getNetwork() 634 c := nw.getController() 635 sb, ok := ep.getSandbox() 636 if !ok { 637 log.G(context.TODO()).WithFields(log.Fields{ 638 "sandboxID": ep.sandboxID, 639 "endpointID": ep.ID(), 640 }).Warn("DNSNames update aborted, sandbox is not present anymore") 641 return nil 642 } 643 644 if c.isAgent() { 645 if err := ep.deleteServiceInfoFromCluster(sb, true, "UpdateDNSNames"); err != nil { 646 return types.InternalErrorf("could not delete service state for endpoint %s from cluster on UpdateDNSNames: %v", ep.Name(), err) 647 } 648 649 ep.dnsNames = dnsNames 650 if err := ep.addServiceInfoToCluster(sb); err != nil { 651 return types.InternalErrorf("could not add service state for endpoint %s to cluster on UpdateDNSNames: %v", ep.Name(), err) 652 } 653 } else { 654 nw.updateSvcRecord(ep, false) 655 656 ep.dnsNames = dnsNames 657 nw.updateSvcRecord(ep, true) 658 } 659 660 // Update the store with the updated name 661 if err := c.updateToStore(ep); err != nil { 662 return err 663 } 664 665 return nil 666 } 667 668 func (ep *Endpoint) hasInterface(iName string) bool { 669 ep.mu.Lock() 670 defer ep.mu.Unlock() 671 672 return ep.iface != nil && ep.iface.srcName == iName 673 } 674 675 // Leave detaches the network resources populated in the sandbox. 676 func (ep *Endpoint) Leave(sb *Sandbox) error { 677 if sb == nil || sb.ID() == "" || sb.Key() == "" { 678 return types.InvalidParameterErrorf("invalid Sandbox passed to endpoint leave: %v", sb) 679 } 680 681 sb.joinLeaveStart() 682 defer sb.joinLeaveEnd() 683 684 return ep.sbLeave(sb, false) 685 } 686 687 func (ep *Endpoint) sbLeave(sb *Sandbox, force bool) error { 688 n, err := ep.getNetworkFromStore() 689 if err != nil { 690 return fmt.Errorf("failed to get network from store during leave: %v", err) 691 } 692 693 ep, err = n.getEndpointFromStore(ep.ID()) 694 if err != nil { 695 return fmt.Errorf("failed to get endpoint from store during leave: %v", err) 696 } 697 698 ep.mu.Lock() 699 sid := ep.sandboxID 700 ep.mu.Unlock() 701 702 if sid == "" { 703 return types.ForbiddenErrorf("cannot leave endpoint with no attached sandbox") 704 } 705 if sid != sb.ID() { 706 return types.ForbiddenErrorf("unexpected sandbox ID in leave request. Expected %s. Got %s", ep.sandboxID, sb.ID()) 707 } 708 709 d, err := n.driver(!force) 710 if err != nil { 711 return fmt.Errorf("failed to get driver during endpoint leave: %v", err) 712 } 713 714 ep.mu.Lock() 715 ep.sandboxID = "" 716 ep.network = n 717 ep.mu.Unlock() 718 719 // Current endpoint providing external connectivity to the sandbox 720 extEp := sb.getGatewayEndpoint() 721 moveExtConn := extEp != nil && (extEp.ID() == ep.ID()) 722 723 if d != nil { 724 if moveExtConn { 725 log.G(context.TODO()).Debugf("Revoking external connectivity on endpoint %s (%s)", ep.Name(), ep.ID()) 726 if err := d.RevokeExternalConnectivity(n.id, ep.id); err != nil { 727 log.G(context.TODO()).Warnf("driver failed revoking external connectivity on endpoint %s (%s): %v", 728 ep.Name(), ep.ID(), err) 729 } 730 } 731 732 if err := d.Leave(n.id, ep.id); err != nil { 733 if _, ok := err.(types.MaskableError); !ok { 734 log.G(context.TODO()).Warnf("driver error disconnecting container %s : %v", ep.name, err) 735 } 736 } 737 } 738 739 if err := ep.deleteServiceInfoFromCluster(sb, true, "sbLeave"); err != nil { 740 log.G(context.TODO()).Warnf("Failed to clean up service info on container %s disconnect: %v", ep.name, err) 741 } 742 743 if err := sb.clearNetworkResources(ep); err != nil { 744 log.G(context.TODO()).Warnf("Failed to clean up network resources on container %s disconnect: %v", ep.name, err) 745 } 746 747 // Update the store about the sandbox detach only after we 748 // have completed sb.clearNetworkresources above to avoid 749 // spurious logs when cleaning up the sandbox when the daemon 750 // ungracefully exits and restarts before completing sandbox 751 // detach but after store has been updated. 752 if err := n.getController().updateToStore(ep); err != nil { 753 return err 754 } 755 756 if e := ep.deleteDriverInfoFromCluster(); e != nil { 757 log.G(context.TODO()).Errorf("Failed to delete endpoint state for endpoint %s from cluster: %v", ep.Name(), e) 758 } 759 760 sb.deleteHostsEntries(n.getSvcRecords(ep)) 761 if !sb.inDelete && sb.needDefaultGW() && sb.getEndpointInGWNetwork() == nil { 762 return sb.setupDefaultGW() 763 } 764 765 // New endpoint providing external connectivity for the sandbox 766 extEp = sb.getGatewayEndpoint() 767 if moveExtConn && extEp != nil { 768 log.G(context.TODO()).Debugf("Programming external connectivity on endpoint %s (%s)", extEp.Name(), extEp.ID()) 769 extN, err := extEp.getNetworkFromStore() 770 if err != nil { 771 return fmt.Errorf("failed to get network from store for programming external connectivity during leave: %v", err) 772 } 773 extD, err := extN.driver(true) 774 if err != nil { 775 return fmt.Errorf("failed to get driver for programming external connectivity during leave: %v", err) 776 } 777 if err := extD.ProgramExternalConnectivity(extEp.network.ID(), extEp.ID(), sb.Labels()); err != nil { 778 log.G(context.TODO()).Warnf("driver failed programming external connectivity on endpoint %s: (%s) %v", 779 extEp.Name(), extEp.ID(), err) 780 } 781 } 782 783 if !sb.needDefaultGW() { 784 if err := sb.clearDefaultGW(); err != nil { 785 log.G(context.TODO()).Warnf("Failure while disconnecting sandbox %s (%s) from gateway network: %v", 786 sb.ID(), sb.ContainerID(), err) 787 } 788 } 789 790 return nil 791 } 792 793 // Delete deletes and detaches this endpoint from the network. 794 func (ep *Endpoint) Delete(force bool) error { 795 var err error 796 n, err := ep.getNetworkFromStore() 797 if err != nil { 798 return fmt.Errorf("failed to get network during Delete: %v", err) 799 } 800 801 ep, err = n.getEndpointFromStore(ep.ID()) 802 if err != nil { 803 return fmt.Errorf("failed to get endpoint from store during Delete: %v", err) 804 } 805 806 ep.mu.Lock() 807 epid := ep.id 808 name := ep.name 809 sbid := ep.sandboxID 810 ep.mu.Unlock() 811 812 sb, _ := n.getController().SandboxByID(sbid) 813 if sb != nil && !force { 814 return &ActiveContainerError{name: name, id: epid} 815 } 816 817 if sb != nil { 818 if e := ep.sbLeave(sb, force); e != nil { 819 log.G(context.TODO()).Warnf("failed to leave sandbox for endpoint %s : %v", name, e) 820 } 821 } 822 823 if err = n.getController().deleteFromStore(ep); err != nil { 824 return err 825 } 826 827 defer func() { 828 if err != nil && !force { 829 ep.dbExists = false 830 if e := n.getController().updateToStore(ep); e != nil { 831 log.G(context.TODO()).Warnf("failed to recreate endpoint in store %s : %v", name, e) 832 } 833 } 834 }() 835 836 if !n.getController().isSwarmNode() || n.Scope() != scope.Swarm || !n.driverIsMultihost() { 837 n.updateSvcRecord(ep, false) 838 } 839 840 if err = ep.deleteEndpoint(force); err != nil && !force { 841 return err 842 } 843 844 ep.releaseAddress() 845 846 if err := n.getEpCnt().DecEndpointCnt(); err != nil { 847 log.G(context.TODO()).Warnf("failed to decrement endpoint count for ep %s: %v", ep.ID(), err) 848 } 849 850 return nil 851 } 852 853 func (ep *Endpoint) deleteEndpoint(force bool) error { 854 ep.mu.Lock() 855 n := ep.network 856 name := ep.name 857 epid := ep.id 858 ep.mu.Unlock() 859 860 driver, err := n.driver(!force) 861 if err != nil { 862 return fmt.Errorf("failed to delete endpoint: %v", err) 863 } 864 865 if driver == nil { 866 return nil 867 } 868 869 if err := driver.DeleteEndpoint(n.id, epid); err != nil { 870 if _, ok := err.(types.ForbiddenError); ok { 871 return err 872 } 873 874 if _, ok := err.(types.MaskableError); !ok { 875 log.G(context.TODO()).Warnf("driver error deleting endpoint %s : %v", name, err) 876 } 877 } 878 879 return nil 880 } 881 882 func (ep *Endpoint) getSandbox() (*Sandbox, bool) { 883 c := ep.network.getController() 884 ep.mu.Lock() 885 sid := ep.sandboxID 886 ep.mu.Unlock() 887 888 c.mu.Lock() 889 ps, ok := c.sandboxes[sid] 890 c.mu.Unlock() 891 892 return ps, ok 893 } 894 895 // Return a list of this endpoint's addresses to add to '/etc/hosts'. 896 func (ep *Endpoint) getEtcHostsAddrs() []string { 897 ep.mu.Lock() 898 defer ep.mu.Unlock() 899 900 // Do not update hosts file with internal network's endpoint IP 901 if n := ep.network; n == nil || n.ingress || n.Name() == libnGWNetwork { 902 return nil 903 } 904 905 var addresses []string 906 if ep.iface.addr != nil { 907 addresses = append(addresses, ep.iface.addr.IP.String()) 908 } 909 if ep.iface.addrv6 != nil { 910 addresses = append(addresses, ep.iface.addrv6.IP.String()) 911 } 912 return addresses 913 } 914 915 // EndpointOptionGeneric function returns an option setter for a Generic option defined 916 // in a Dictionary of Key-Value pair 917 func EndpointOptionGeneric(generic map[string]interface{}) EndpointOption { 918 return func(ep *Endpoint) { 919 for k, v := range generic { 920 ep.generic[k] = v 921 } 922 } 923 } 924 925 var ( 926 linkLocalMask = net.CIDRMask(16, 32) 927 linkLocalMaskIPv6 = net.CIDRMask(64, 128) 928 ) 929 930 // CreateOptionIpam function returns an option setter for the ipam configuration for this endpoint 931 func CreateOptionIpam(ipV4, ipV6 net.IP, llIPs []net.IP, ipamOptions map[string]string) EndpointOption { 932 return func(ep *Endpoint) { 933 ep.prefAddress = ipV4 934 ep.prefAddressV6 = ipV6 935 if len(llIPs) != 0 { 936 for _, ip := range llIPs { 937 nw := &net.IPNet{IP: ip, Mask: linkLocalMask} 938 if ip.To4() == nil { 939 nw.Mask = linkLocalMaskIPv6 940 } 941 ep.iface.llAddrs = append(ep.iface.llAddrs, nw) 942 } 943 } 944 ep.ipamOptions = ipamOptions 945 } 946 } 947 948 // CreateOptionExposedPorts function returns an option setter for the container exposed 949 // ports option to be passed to [Network.CreateEndpoint] method. 950 func CreateOptionExposedPorts(exposedPorts []types.TransportPort) EndpointOption { 951 return func(ep *Endpoint) { 952 // Defensive copy 953 eps := make([]types.TransportPort, len(exposedPorts)) 954 copy(eps, exposedPorts) 955 // Store endpoint label and in generic because driver needs it 956 ep.exposedPorts = eps 957 ep.generic[netlabel.ExposedPorts] = eps 958 } 959 } 960 961 // CreateOptionPortMapping function returns an option setter for the mapping 962 // ports option to be passed to [Network.CreateEndpoint] method. 963 func CreateOptionPortMapping(portBindings []types.PortBinding) EndpointOption { 964 return func(ep *Endpoint) { 965 // Store a copy of the bindings as generic data to pass to the driver 966 pbs := make([]types.PortBinding, len(portBindings)) 967 copy(pbs, portBindings) 968 ep.generic[netlabel.PortMap] = pbs 969 } 970 } 971 972 // CreateOptionDNS function returns an option setter for dns entry option to 973 // be passed to container Create method. 974 func CreateOptionDNS(dns []string) EndpointOption { 975 return func(ep *Endpoint) { 976 ep.generic[netlabel.DNSServers] = dns 977 } 978 } 979 980 // CreateOptionDNSNames specifies the list of (non fully qualified) DNS names associated to an endpoint. These will be 981 // used to populate the embedded DNS server. Order matters: first name will be used to generate PTR records. 982 func CreateOptionDNSNames(names []string) EndpointOption { 983 return func(ep *Endpoint) { 984 ep.dnsNames = names 985 } 986 } 987 988 // CreateOptionDisableResolution function returns an option setter to indicate 989 // this endpoint doesn't want embedded DNS server functionality 990 func CreateOptionDisableResolution() EndpointOption { 991 return func(ep *Endpoint) { 992 ep.disableResolution = true 993 } 994 } 995 996 // CreateOptionAlias function returns an option setter for setting endpoint alias 997 func CreateOptionAlias(name string, alias string) EndpointOption { 998 return func(ep *Endpoint) { 999 if ep.aliases == nil { 1000 ep.aliases = make(map[string]string) 1001 } 1002 ep.aliases[alias] = name 1003 } 1004 } 1005 1006 // CreateOptionService function returns an option setter for setting service binding configuration 1007 func CreateOptionService(name, id string, vip net.IP, ingressPorts []*PortConfig, aliases []string) EndpointOption { 1008 return func(ep *Endpoint) { 1009 ep.svcName = name 1010 ep.svcID = id 1011 ep.virtualIP = vip 1012 ep.ingressPorts = ingressPorts 1013 ep.svcAliases = aliases 1014 } 1015 } 1016 1017 // CreateOptionLoadBalancer function returns an option setter for denoting the endpoint is a load balancer for a network 1018 func CreateOptionLoadBalancer() EndpointOption { 1019 return func(ep *Endpoint) { 1020 ep.loadBalancer = true 1021 } 1022 } 1023 1024 // JoinOptionPriority function returns an option setter for priority option to 1025 // be passed to the endpoint.Join() method. 1026 func JoinOptionPriority(prio int) EndpointOption { 1027 return func(ep *Endpoint) { 1028 // ep lock already acquired 1029 c := ep.network.getController() 1030 c.mu.Lock() 1031 sb, ok := c.sandboxes[ep.sandboxID] 1032 c.mu.Unlock() 1033 if !ok { 1034 log.G(context.TODO()).Errorf("Could not set endpoint priority value during Join to endpoint %s: No sandbox id present in endpoint", ep.id) 1035 return 1036 } 1037 sb.epPriority[ep.id] = prio 1038 } 1039 } 1040 1041 func (ep *Endpoint) assignAddress(ipam ipamapi.Ipam, assignIPv4, assignIPv6 bool) error { 1042 var err error 1043 1044 n := ep.getNetwork() 1045 if n.hasSpecialDriver() { 1046 return nil 1047 } 1048 1049 log.G(context.TODO()).Debugf("Assigning addresses for endpoint %s's interface on network %s", ep.Name(), n.Name()) 1050 1051 if assignIPv4 { 1052 if err = ep.assignAddressVersion(4, ipam); err != nil { 1053 return err 1054 } 1055 } 1056 1057 if assignIPv6 { 1058 err = ep.assignAddressVersion(6, ipam) 1059 } 1060 1061 return err 1062 } 1063 1064 func (ep *Endpoint) assignAddressVersion(ipVer int, ipam ipamapi.Ipam) error { 1065 var ( 1066 poolID *string 1067 address **net.IPNet 1068 prefAdd net.IP 1069 progAdd net.IP 1070 ) 1071 1072 n := ep.getNetwork() 1073 switch ipVer { 1074 case 4: 1075 poolID = &ep.iface.v4PoolID 1076 address = &ep.iface.addr 1077 prefAdd = ep.prefAddress 1078 case 6: 1079 poolID = &ep.iface.v6PoolID 1080 address = &ep.iface.addrv6 1081 prefAdd = ep.prefAddressV6 1082 default: 1083 return types.InternalErrorf("incorrect ip version number passed: %d", ipVer) 1084 } 1085 1086 ipInfo := n.getIPInfo(ipVer) 1087 1088 // ipv6 address is not mandatory 1089 if len(ipInfo) == 0 && ipVer == 6 { 1090 return nil 1091 } 1092 1093 // The address to program may be chosen by the user or by the network driver in one specific 1094 // case to support backward compatibility with `docker daemon --fixed-cidrv6` use case 1095 if prefAdd != nil { 1096 progAdd = prefAdd 1097 } else if *address != nil { 1098 progAdd = (*address).IP 1099 } 1100 1101 for _, d := range ipInfo { 1102 if progAdd != nil && !d.Pool.Contains(progAdd) { 1103 continue 1104 } 1105 addr, _, err := ipam.RequestAddress(d.PoolID, progAdd, ep.ipamOptions) 1106 if err == nil { 1107 ep.mu.Lock() 1108 *address = addr 1109 *poolID = d.PoolID 1110 ep.mu.Unlock() 1111 return nil 1112 } 1113 if err != ipamapi.ErrNoAvailableIPs || progAdd != nil { 1114 return err 1115 } 1116 } 1117 if progAdd != nil { 1118 return types.InvalidParameterErrorf("invalid address %s: It does not belong to any of this network's subnets", prefAdd) 1119 } 1120 return fmt.Errorf("no available IPv%d addresses on this network's address pools: %s (%s)", ipVer, n.Name(), n.ID()) 1121 } 1122 1123 func (ep *Endpoint) releaseAddress() { 1124 n := ep.getNetwork() 1125 if n.hasSpecialDriver() { 1126 return 1127 } 1128 1129 log.G(context.TODO()).Debugf("Releasing addresses for endpoint %s's interface on network %s", ep.Name(), n.Name()) 1130 1131 ipam, _, err := n.getController().getIPAMDriver(n.ipamType) 1132 if err != nil { 1133 log.G(context.TODO()).Warnf("Failed to retrieve ipam driver to release interface address on delete of endpoint %s (%s): %v", ep.Name(), ep.ID(), err) 1134 return 1135 } 1136 1137 if ep.iface.addr != nil { 1138 if err := ipam.ReleaseAddress(ep.iface.v4PoolID, ep.iface.addr.IP); err != nil { 1139 log.G(context.TODO()).Warnf("Failed to release ip address %s on delete of endpoint %s (%s): %v", ep.iface.addr.IP, ep.Name(), ep.ID(), err) 1140 } 1141 } 1142 1143 if ep.iface.addrv6 != nil { 1144 if err := ipam.ReleaseAddress(ep.iface.v6PoolID, ep.iface.addrv6.IP); err != nil { 1145 log.G(context.TODO()).Warnf("Failed to release ip address %s on delete of endpoint %s (%s): %v", ep.iface.addrv6.IP, ep.Name(), ep.ID(), err) 1146 } 1147 } 1148 } 1149 1150 func (c *Controller) cleanupLocalEndpoints() error { 1151 // Get used endpoints 1152 eps := make(map[string]interface{}) 1153 for _, sb := range c.sandboxes { 1154 for _, ep := range sb.endpoints { 1155 eps[ep.id] = true 1156 } 1157 } 1158 nl, err := c.getNetworks() 1159 if err != nil { 1160 return fmt.Errorf("could not get list of networks: %v", err) 1161 } 1162 1163 for _, n := range nl { 1164 if n.ConfigOnly() { 1165 continue 1166 } 1167 epl, err := n.getEndpointsFromStore() 1168 if err != nil { 1169 log.G(context.TODO()).Warnf("Could not get list of endpoints in network %s during endpoint cleanup: %v", n.name, err) 1170 continue 1171 } 1172 1173 for _, ep := range epl { 1174 if _, ok := eps[ep.id]; ok { 1175 continue 1176 } 1177 log.G(context.TODO()).Infof("Removing stale endpoint %s (%s)", ep.name, ep.id) 1178 if err := ep.Delete(true); err != nil { 1179 log.G(context.TODO()).Warnf("Could not delete local endpoint %s during endpoint cleanup: %v", ep.name, err) 1180 } 1181 } 1182 1183 epl, err = n.getEndpointsFromStore() 1184 if err != nil { 1185 log.G(context.TODO()).Warnf("Could not get list of endpoints in network %s for count update: %v", n.name, err) 1186 continue 1187 } 1188 1189 epCnt := n.getEpCnt().EndpointCnt() 1190 if epCnt != uint64(len(epl)) { 1191 log.G(context.TODO()).Infof("Fixing inconsistent endpoint_cnt for network %s. Expected=%d, Actual=%d", n.name, len(epl), epCnt) 1192 if err := n.getEpCnt().setCnt(uint64(len(epl))); err != nil { 1193 log.G(context.TODO()).WithField("network", n.name).WithError(err).Warn("Error while fixing inconsistent endpoint_cnt for network") 1194 } 1195 } 1196 } 1197 1198 return nil 1199 }