1package libnetwork 2 3import ( 4 "encoding/json" 5 "fmt" 6 "net" 7 "sort" 8 "strings" 9 "sync" 10 "time" 11 12 "github.com/docker/libnetwork/etchosts" 13 "github.com/docker/libnetwork/netlabel" 14 "github.com/docker/libnetwork/osl" 15 "github.com/docker/libnetwork/types" 16 "github.com/sirupsen/logrus" 17) 18 19// Sandbox provides the control over the network container entity. It is a one to one mapping with the container. 20type Sandbox interface { 21 // ID returns the ID of the sandbox 22 ID() string 23 // Key returns the sandbox's key 24 Key() string 25 // ContainerID returns the container id associated to this sandbox 26 ContainerID() string 27 // Labels returns the sandbox's labels 28 Labels() map[string]interface{} 29 // Statistics retrieves the interfaces' statistics for the sandbox 30 Statistics() (map[string]*types.InterfaceStatistics, error) 31 // Refresh leaves all the endpoints, resets and re-applies the options, 32 // re-joins all the endpoints without destroying the osl sandbox 33 Refresh(options ...SandboxOption) error 34 // SetKey updates the Sandbox Key 35 SetKey(key string) error 36 // Rename changes the name of all attached Endpoints 37 Rename(name string) error 38 // Delete destroys this container after detaching it from all connected endpoints. 39 Delete() error 40 // Endpoints returns all the endpoints connected to the sandbox 41 Endpoints() []Endpoint 42 // ResolveService returns all the backend details about the containers or hosts 43 // backing a service. Its purpose is to satisfy an SRV query 44 ResolveService(name string) ([]*net.SRV, []net.IP) 45 // EnableService makes a managed container's service available by adding the 46 // endpoint to the service load balancer and service discovery 47 EnableService() error 48 // DisableService removes a managed container's endpoints from the load balancer 49 // and service discovery 50 DisableService() error 51} 52 53// SandboxOption is an option setter function type used to pass various options to 54// NewNetContainer method. The various setter functions of type SandboxOption are 55// provided by libnetwork, they look like ContainerOptionXXXX(...) 56type SandboxOption func(sb *sandbox) 57 58func (sb *sandbox) processOptions(options ...SandboxOption) { 59 for _, opt := range options { 60 if opt != nil { 61 opt(sb) 62 } 63 } 64} 65 66type sandbox struct { 67 id string 68 containerID string 69 config containerConfig 70 extDNS []extDNSEntry 71 osSbox osl.Sandbox 72 controller *controller 73 resolver Resolver 74 resolverOnce sync.Once 75 refCnt int 76 endpoints []*endpoint 77 epPriority map[string]int 78 populatedEndpoints map[string]struct{} 79 joinLeaveDone chan struct{} 80 dbIndex uint64 81 dbExists bool 82 isStub bool 83 inDelete bool 84 ingress bool 85 ndotsSet bool 86 oslTypes []osl.SandboxType // slice of properties of this sandbox 87 loadBalancerNID string // NID that this SB is a load balancer for 88 sync.Mutex 89 // This mutex is used to serialize service related operation for an endpoint 90 // The lock is here because the endpoint is saved into the store so is not unique 91 Service sync.Mutex 92} 93 94// These are the container configs used to customize container /etc/hosts file. 95type hostsPathConfig struct { 96 hostName string 97 domainName string 98 hostsPath string 99 originHostsPath string 100 extraHosts []extraHost 101 parentUpdates []parentUpdate 102} 103 104type parentUpdate struct { 105 cid string 106 name string 107 ip string 108} 109 110type extraHost struct { 111 name string 112 IP string 113} 114 115// These are the container configs used to customize container /etc/resolv.conf file. 116type resolvConfPathConfig struct { 117 resolvConfPath string 118 originResolvConfPath string 119 resolvConfHashFile string 120 dnsList []string 121 dnsSearchList []string 122 dnsOptionsList []string 123} 124 125type containerConfig struct { 126 hostsPathConfig 127 resolvConfPathConfig 128 generic map[string]interface{} 129 useDefaultSandBox bool 130 useExternalKey bool 131 prio int // higher the value, more the priority 132 exposedPorts []types.TransportPort 133} 134 135const ( 136 resolverIPSandbox = "127.0.0.11" 137) 138 139func (sb *sandbox) ID() string { 140 return sb.id 141} 142 143func (sb *sandbox) ContainerID() string { 144 return sb.containerID 145} 146 147func (sb *sandbox) Key() string { 148 if sb.config.useDefaultSandBox { 149 return osl.GenerateKey("default") 150 } 151 return osl.GenerateKey(sb.id) 152} 153 154func (sb *sandbox) Labels() map[string]interface{} { 155 sb.Lock() 156 defer sb.Unlock() 157 opts := make(map[string]interface{}, len(sb.config.generic)) 158 for k, v := range sb.config.generic { 159 opts[k] = v 160 } 161 return opts 162} 163 164func (sb *sandbox) Statistics() (map[string]*types.InterfaceStatistics, error) { 165 m := make(map[string]*types.InterfaceStatistics) 166 167 sb.Lock() 168 osb := sb.osSbox 169 sb.Unlock() 170 if osb == nil { 171 return m, nil 172 } 173 174 var err error 175 for _, i := range osb.Info().Interfaces() { 176 if m[i.DstName()], err = i.Statistics(); err != nil { 177 return m, err 178 } 179 } 180 181 return m, nil 182} 183 184func (sb *sandbox) Delete() error { 185 return sb.delete(false) 186} 187 188func (sb *sandbox) delete(force bool) error { 189 sb.Lock() 190 if sb.inDelete { 191 sb.Unlock() 192 return types.ForbiddenErrorf("another sandbox delete in progress") 193 } 194 // Set the inDelete flag. This will ensure that we don't 195 // update the store until we have completed all the endpoint 196 // leaves and deletes. And when endpoint leaves and deletes 197 // are completed then we can finally delete the sandbox object 198 // altogether from the data store. If the daemon exits 199 // ungracefully in the middle of a sandbox delete this way we 200 // will have all the references to the endpoints in the 201 // sandbox so that we can clean them up when we restart 202 sb.inDelete = true 203 sb.Unlock() 204 205 c := sb.controller 206 207 // Detach from all endpoints 208 retain := false 209 for _, ep := range sb.getConnectedEndpoints() { 210 // gw network endpoint detach and removal are automatic 211 if ep.endpointInGWNetwork() && !force { 212 continue 213 } 214 // Retain the sanbdox if we can't obtain the network from store. 215 if _, err := c.getNetworkFromStore(ep.getNetwork().ID()); err != nil { 216 if c.isDistributedControl() { 217 retain = true 218 } 219 logrus.Warnf("Failed getting network for ep %s during sandbox %s delete: %v", ep.ID(), sb.ID(), err) 220 continue 221 } 222 223 if !force { 224 if err := ep.Leave(sb); err != nil { 225 logrus.Warnf("Failed detaching sandbox %s from endpoint %s: %v\n", sb.ID(), ep.ID(), err) 226 } 227 } 228 229 if err := ep.Delete(force); err != nil { 230 logrus.Warnf("Failed deleting endpoint %s: %v\n", ep.ID(), err) 231 } 232 } 233 234 if retain { 235 sb.Lock() 236 sb.inDelete = false 237 sb.Unlock() 238 return fmt.Errorf("could not cleanup all the endpoints in container %s / sandbox %s", sb.containerID, sb.id) 239 } 240 // Container is going away. Path cache in etchosts is most 241 // likely not required any more. Drop it. 242 etchosts.Drop(sb.config.hostsPath) 243 244 if sb.resolver != nil { 245 sb.resolver.Stop() 246 } 247 248 if sb.osSbox != nil && !sb.config.useDefaultSandBox { 249 sb.osSbox.Destroy() 250 } 251 252 if err := sb.storeDelete(); err != nil { 253 logrus.Warnf("Failed to delete sandbox %s from store: %v", sb.ID(), err) 254 } 255 256 c.Lock() 257 if sb.ingress { 258 c.ingressSandbox = nil 259 } 260 delete(c.sandboxes, sb.ID()) 261 c.Unlock() 262 263 return nil 264} 265 266func (sb *sandbox) Rename(name string) error { 267 var err error 268 269 for _, ep := range sb.getConnectedEndpoints() { 270 if ep.endpointInGWNetwork() { 271 continue 272 } 273 274 oldName := ep.Name() 275 lEp := ep 276 if err = ep.rename(name); err != nil { 277 break 278 } 279 280 defer func() { 281 if err != nil { 282 lEp.rename(oldName) 283 } 284 }() 285 } 286 287 return err 288} 289 290func (sb *sandbox) Refresh(options ...SandboxOption) error { 291 // Store connected endpoints 292 epList := sb.getConnectedEndpoints() 293 294 // Detach from all endpoints 295 for _, ep := range epList { 296 if err := ep.Leave(sb); err != nil { 297 logrus.Warnf("Failed detaching sandbox %s from endpoint %s: %v\n", sb.ID(), ep.ID(), err) 298 } 299 } 300 301 // Re-apply options 302 sb.config = containerConfig{} 303 sb.processOptions(options...) 304 305 // Setup discovery files 306 if err := sb.setupResolutionFiles(); err != nil { 307 return err 308 } 309 310 // Re-connect to all endpoints 311 for _, ep := range epList { 312 if err := ep.Join(sb); err != nil { 313 logrus.Warnf("Failed attach sandbox %s to endpoint %s: %v\n", sb.ID(), ep.ID(), err) 314 } 315 } 316 317 return nil 318} 319 320func (sb *sandbox) MarshalJSON() ([]byte, error) { 321 sb.Lock() 322 defer sb.Unlock() 323 324 // We are just interested in the container ID. This can be expanded to include all of containerInfo if there is a need 325 return json.Marshal(sb.id) 326} 327 328func (sb *sandbox) UnmarshalJSON(b []byte) (err error) { 329 sb.Lock() 330 defer sb.Unlock() 331 332 var id string 333 if err := json.Unmarshal(b, &id); err != nil { 334 return err 335 } 336 sb.id = id 337 return nil 338} 339 340func (sb *sandbox) Endpoints() []Endpoint { 341 sb.Lock() 342 defer sb.Unlock() 343 344 endpoints := make([]Endpoint, len(sb.endpoints)) 345 for i, ep := range sb.endpoints { 346 endpoints[i] = ep 347 } 348 return endpoints 349} 350 351func (sb *sandbox) getConnectedEndpoints() []*endpoint { 352 sb.Lock() 353 defer sb.Unlock() 354 355 eps := make([]*endpoint, len(sb.endpoints)) 356 copy(eps, sb.endpoints) 357 358 return eps 359} 360 361func (sb *sandbox) addEndpoint(ep *endpoint) { 362 sb.Lock() 363 defer sb.Unlock() 364 365 l := len(sb.endpoints) 366 i := sort.Search(l, func(j int) bool { 367 return ep.Less(sb.endpoints[j]) 368 }) 369 370 sb.endpoints = append(sb.endpoints, nil) 371 copy(sb.endpoints[i+1:], sb.endpoints[i:]) 372 sb.endpoints[i] = ep 373} 374 375func (sb *sandbox) removeEndpoint(ep *endpoint) { 376 sb.Lock() 377 defer sb.Unlock() 378 379 sb.removeEndpointRaw(ep) 380} 381 382func (sb *sandbox) removeEndpointRaw(ep *endpoint) { 383 for i, e := range sb.endpoints { 384 if e == ep { 385 sb.endpoints = append(sb.endpoints[:i], sb.endpoints[i+1:]...) 386 return 387 } 388 } 389} 390 391func (sb *sandbox) getEndpoint(id string) *endpoint { 392 sb.Lock() 393 defer sb.Unlock() 394 395 for _, ep := range sb.endpoints { 396 if ep.id == id { 397 return ep 398 } 399 } 400 401 return nil 402} 403 404func (sb *sandbox) updateGateway(ep *endpoint) error { 405 sb.Lock() 406 osSbox := sb.osSbox 407 sb.Unlock() 408 if osSbox == nil { 409 return nil 410 } 411 osSbox.UnsetGateway() 412 osSbox.UnsetGatewayIPv6() 413 414 if ep == nil { 415 return nil 416 } 417 418 ep.Lock() 419 joinInfo := ep.joinInfo 420 ep.Unlock() 421 422 if err := osSbox.SetGateway(joinInfo.gw); err != nil { 423 return fmt.Errorf("failed to set gateway while updating gateway: %v", err) 424 } 425 426 if err := osSbox.SetGatewayIPv6(joinInfo.gw6); err != nil { 427 return fmt.Errorf("failed to set IPv6 gateway while updating gateway: %v", err) 428 } 429 430 return nil 431} 432 433func (sb *sandbox) HandleQueryResp(name string, ip net.IP) { 434 for _, ep := range sb.getConnectedEndpoints() { 435 n := ep.getNetwork() 436 n.HandleQueryResp(name, ip) 437 } 438} 439 440func (sb *sandbox) ResolveIP(ip string) string { 441 var svc string 442 logrus.Debugf("IP To resolve %v", ip) 443 444 for _, ep := range sb.getConnectedEndpoints() { 445 n := ep.getNetwork() 446 svc = n.ResolveIP(ip) 447 if len(svc) != 0 { 448 return svc 449 } 450 } 451 452 return svc 453} 454 455func (sb *sandbox) ExecFunc(f func()) error { 456 sb.Lock() 457 osSbox := sb.osSbox 458 sb.Unlock() 459 if osSbox != nil { 460 return osSbox.InvokeFunc(f) 461 } 462 return fmt.Errorf("osl sandbox unavailable in ExecFunc for %v", sb.ContainerID()) 463} 464 465func (sb *sandbox) ResolveService(name string) ([]*net.SRV, []net.IP) { 466 srv := []*net.SRV{} 467 ip := []net.IP{} 468 469 logrus.Debugf("Service name To resolve: %v", name) 470 471 // There are DNS implementations that allow SRV queries for names not in 472 // the format defined by RFC 2782. Hence specific validations checks are 473 // not done 474 parts := strings.Split(name, ".") 475 if len(parts) < 3 { 476 return nil, nil 477 } 478 479 for _, ep := range sb.getConnectedEndpoints() { 480 n := ep.getNetwork() 481 482 srv, ip = n.ResolveService(name) 483 if len(srv) > 0 { 484 break 485 } 486 } 487 return srv, ip 488} 489 490func getDynamicNwEndpoints(epList []*endpoint) []*endpoint { 491 eps := []*endpoint{} 492 for _, ep := range epList { 493 n := ep.getNetwork() 494 if n.dynamic && !n.ingress { 495 eps = append(eps, ep) 496 } 497 } 498 return eps 499} 500 501func getIngressNwEndpoint(epList []*endpoint) *endpoint { 502 for _, ep := range epList { 503 n := ep.getNetwork() 504 if n.ingress { 505 return ep 506 } 507 } 508 return nil 509} 510 511func getLocalNwEndpoints(epList []*endpoint) []*endpoint { 512 eps := []*endpoint{} 513 for _, ep := range epList { 514 n := ep.getNetwork() 515 if !n.dynamic && !n.ingress { 516 eps = append(eps, ep) 517 } 518 } 519 return eps 520} 521 522func (sb *sandbox) ResolveName(name string, ipType int) ([]net.IP, bool) { 523 // Embedded server owns the docker network domain. Resolution should work 524 // for both container_name and container_name.network_name 525 // We allow '.' in service name and network name. For a name a.b.c.d the 526 // following have to tried; 527 // {a.b.c.d in the networks container is connected to} 528 // {a.b.c in network d}, 529 // {a.b in network c.d}, 530 // {a in network b.c.d}, 531 532 logrus.Debugf("Name To resolve: %v", name) 533 name = strings.TrimSuffix(name, ".") 534 reqName := []string{name} 535 networkName := []string{""} 536 537 if strings.Contains(name, ".") { 538 var i int 539 dup := name 540 for { 541 if i = strings.LastIndex(dup, "."); i == -1 { 542 break 543 } 544 networkName = append(networkName, name[i+1:]) 545 reqName = append(reqName, name[:i]) 546 547 dup = dup[:i] 548 } 549 } 550 551 epList := sb.getConnectedEndpoints() 552 553 // In swarm mode services with exposed ports are connected to user overlay 554 // network, ingress network and docker_gwbridge network. Name resolution 555 // should prioritize returning the VIP/IPs on user overlay network. 556 newList := []*endpoint{} 557 if !sb.controller.isDistributedControl() { 558 newList = append(newList, getDynamicNwEndpoints(epList)...) 559 ingressEP := getIngressNwEndpoint(epList) 560 if ingressEP != nil { 561 newList = append(newList, ingressEP) 562 } 563 newList = append(newList, getLocalNwEndpoints(epList)...) 564 epList = newList 565 } 566 567 for i := 0; i < len(reqName); i++ { 568 569 // First check for local container alias 570 ip, ipv6Miss := sb.resolveName(reqName[i], networkName[i], epList, true, ipType) 571 if ip != nil { 572 return ip, false 573 } 574 if ipv6Miss { 575 return ip, ipv6Miss 576 } 577 578 // Resolve the actual container name 579 ip, ipv6Miss = sb.resolveName(reqName[i], networkName[i], epList, false, ipType) 580 if ip != nil { 581 return ip, false 582 } 583 if ipv6Miss { 584 return ip, ipv6Miss 585 } 586 } 587 return nil, false 588} 589 590func (sb *sandbox) resolveName(req string, networkName string, epList []*endpoint, alias bool, ipType int) ([]net.IP, bool) { 591 var ipv6Miss bool 592 593 for _, ep := range epList { 594 name := req 595 n := ep.getNetwork() 596 597 if networkName != "" && networkName != n.Name() { 598 continue 599 } 600 601 if alias { 602 if ep.aliases == nil { 603 continue 604 } 605 606 var ok bool 607 ep.Lock() 608 name, ok = ep.aliases[req] 609 ep.Unlock() 610 if !ok { 611 continue 612 } 613 } else { 614 // If it is a regular lookup and if the requested name is an alias 615 // don't perform a svc lookup for this endpoint. 616 ep.Lock() 617 if _, ok := ep.aliases[req]; ok { 618 ep.Unlock() 619 continue 620 } 621 ep.Unlock() 622 } 623 624 ip, miss := n.ResolveName(name, ipType) 625 626 if ip != nil { 627 return ip, false 628 } 629 630 if miss { 631 ipv6Miss = miss 632 } 633 } 634 return nil, ipv6Miss 635} 636 637func (sb *sandbox) SetKey(basePath string) error { 638 start := time.Now() 639 defer func() { 640 logrus.Debugf("sandbox set key processing took %s for container %s", time.Since(start), sb.ContainerID()) 641 }() 642 643 if basePath == "" { 644 return types.BadRequestErrorf("invalid sandbox key") 645 } 646 647 sb.Lock() 648 if sb.inDelete { 649 sb.Unlock() 650 return types.ForbiddenErrorf("failed to SetKey: sandbox %q delete in progress", sb.id) 651 } 652 oldosSbox := sb.osSbox 653 sb.Unlock() 654 655 if oldosSbox != nil { 656 // If we already have an OS sandbox, release the network resources from that 657 // and destroy the OS snab. We are moving into a new home further down. Note that none 658 // of the network resources gets destroyed during the move. 659 sb.releaseOSSbox() 660 } 661 662 osSbox, err := osl.GetSandboxForExternalKey(basePath, sb.Key()) 663 if err != nil { 664 return err 665 } 666 667 sb.Lock() 668 sb.osSbox = osSbox 669 sb.Unlock() 670 671 // If the resolver was setup before stop it and set it up in the 672 // new osl sandbox. 673 if oldosSbox != nil && sb.resolver != nil { 674 sb.resolver.Stop() 675 676 if err := sb.osSbox.InvokeFunc(sb.resolver.SetupFunc(0)); err == nil { 677 if err := sb.resolver.Start(); err != nil { 678 logrus.Errorf("Resolver Start failed for container %s, %q", sb.ContainerID(), err) 679 } 680 } else { 681 logrus.Errorf("Resolver Setup Function failed for container %s, %q", sb.ContainerID(), err) 682 } 683 } 684 685 for _, ep := range sb.getConnectedEndpoints() { 686 if err = sb.populateNetworkResources(ep); err != nil { 687 return err 688 } 689 } 690 return nil 691} 692 693func (sb *sandbox) EnableService() (err error) { 694 logrus.Debugf("EnableService %s START", sb.containerID) 695 defer func() { 696 if err != nil { 697 sb.DisableService() 698 } 699 }() 700 for _, ep := range sb.getConnectedEndpoints() { 701 if !ep.isServiceEnabled() { 702 if err := ep.addServiceInfoToCluster(sb); err != nil { 703 return fmt.Errorf("could not update state for endpoint %s into cluster: %v", ep.Name(), err) 704 } 705 ep.enableService() 706 } 707 } 708 logrus.Debugf("EnableService %s DONE", sb.containerID) 709 return nil 710} 711 712func (sb *sandbox) DisableService() (err error) { 713 logrus.Debugf("DisableService %s START", sb.containerID) 714 failedEps := []string{} 715 defer func() { 716 if len(failedEps) > 0 { 717 err = fmt.Errorf("failed to disable service on sandbox:%s, for endpoints %s", sb.ID(), strings.Join(failedEps, ",")) 718 } 719 }() 720 for _, ep := range sb.getConnectedEndpoints() { 721 if ep.isServiceEnabled() { 722 if err := ep.deleteServiceInfoFromCluster(sb, false, "DisableService"); err != nil { 723 failedEps = append(failedEps, ep.Name()) 724 logrus.Warnf("failed update state for endpoint %s into cluster: %v", ep.Name(), err) 725 } 726 ep.disableService() 727 } 728 } 729 logrus.Debugf("DisableService %s DONE", sb.containerID) 730 return nil 731} 732 733func releaseOSSboxResources(osSbox osl.Sandbox, ep *endpoint) { 734 for _, i := range osSbox.Info().Interfaces() { 735 // Only remove the interfaces owned by this endpoint from the sandbox. 736 if ep.hasInterface(i.SrcName()) { 737 if err := i.Remove(); err != nil { 738 logrus.Debugf("Remove interface %s failed: %v", i.SrcName(), err) 739 } 740 } 741 } 742 743 ep.Lock() 744 joinInfo := ep.joinInfo 745 ep.Unlock() 746 747 if joinInfo == nil { 748 return 749 } 750 751 // Remove non-interface routes. 752 for _, r := range joinInfo.StaticRoutes { 753 if err := osSbox.RemoveStaticRoute(r); err != nil { 754 logrus.Debugf("Remove route failed: %v", err) 755 } 756 } 757} 758 759func (sb *sandbox) releaseOSSbox() { 760 sb.Lock() 761 osSbox := sb.osSbox 762 sb.osSbox = nil 763 sb.Unlock() 764 765 if osSbox == nil { 766 return 767 } 768 769 for _, ep := range sb.getConnectedEndpoints() { 770 releaseOSSboxResources(osSbox, ep) 771 } 772 773 osSbox.Destroy() 774} 775 776func (sb *sandbox) restoreOslSandbox() error { 777 var routes []*types.StaticRoute 778 779 // restore osl sandbox 780 Ifaces := make(map[string][]osl.IfaceOption) 781 for _, ep := range sb.endpoints { 782 var ifaceOptions []osl.IfaceOption 783 ep.Lock() 784 joinInfo := ep.joinInfo 785 i := ep.iface 786 ep.Unlock() 787 788 if i == nil { 789 logrus.Errorf("error restoring endpoint %s for container %s", ep.Name(), sb.ContainerID()) 790 continue 791 } 792 793 ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().Address(i.addr), sb.osSbox.InterfaceOptions().Routes(i.routes)) 794 if i.addrv6 != nil && i.addrv6.IP.To16() != nil { 795 ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().AddressIPv6(i.addrv6)) 796 } 797 if i.mac != nil { 798 ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().MacAddress(i.mac)) 799 } 800 if len(i.llAddrs) != 0 { 801 ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().LinkLocalAddresses(i.llAddrs)) 802 } 803 Ifaces[fmt.Sprintf("%s+%s", i.srcName, i.dstPrefix)] = ifaceOptions 804 if joinInfo != nil { 805 routes = append(routes, joinInfo.StaticRoutes...) 806 } 807 if ep.needResolver() { 808 sb.startResolver(true) 809 } 810 } 811 812 gwep := sb.getGatewayEndpoint() 813 if gwep == nil { 814 return nil 815 } 816 817 // restore osl sandbox 818 err := sb.osSbox.Restore(Ifaces, routes, gwep.joinInfo.gw, gwep.joinInfo.gw6) 819 return err 820} 821 822func (sb *sandbox) populateNetworkResources(ep *endpoint) error { 823 sb.Lock() 824 if sb.osSbox == nil { 825 sb.Unlock() 826 return nil 827 } 828 inDelete := sb.inDelete 829 sb.Unlock() 830 831 ep.Lock() 832 joinInfo := ep.joinInfo 833 i := ep.iface 834 ep.Unlock() 835 836 if ep.needResolver() { 837 sb.startResolver(false) 838 } 839 840 if i != nil && i.srcName != "" { 841 var ifaceOptions []osl.IfaceOption 842 843 ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().Address(i.addr), sb.osSbox.InterfaceOptions().Routes(i.routes)) 844 if i.addrv6 != nil && i.addrv6.IP.To16() != nil { 845 ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().AddressIPv6(i.addrv6)) 846 } 847 if len(i.llAddrs) != 0 { 848 ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().LinkLocalAddresses(i.llAddrs)) 849 } 850 if i.mac != nil { 851 ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().MacAddress(i.mac)) 852 } 853 854 if err := sb.osSbox.AddInterface(i.srcName, i.dstPrefix, ifaceOptions...); err != nil { 855 return fmt.Errorf("failed to add interface %s to sandbox: %v", i.srcName, err) 856 } 857 } 858 859 if joinInfo != nil { 860 // Set up non-interface routes. 861 for _, r := range joinInfo.StaticRoutes { 862 if err := sb.osSbox.AddStaticRoute(r); err != nil { 863 return fmt.Errorf("failed to add static route %s: %v", r.Destination.String(), err) 864 } 865 } 866 } 867 868 if ep == sb.getGatewayEndpoint() { 869 if err := sb.updateGateway(ep); err != nil { 870 return err 871 } 872 } 873 874 // Make sure to add the endpoint to the populated endpoint set 875 // before populating loadbalancers. 876 sb.Lock() 877 sb.populatedEndpoints[ep.ID()] = struct{}{} 878 sb.Unlock() 879 880 // Populate load balancer only after updating all the other 881 // information including gateway and other routes so that 882 // loadbalancers are populated all the network state is in 883 // place in the sandbox. 884 sb.populateLoadBalancers(ep) 885 886 // Only update the store if we did not come here as part of 887 // sandbox delete. If we came here as part of delete then do 888 // not bother updating the store. The sandbox object will be 889 // deleted anyway 890 if !inDelete { 891 return sb.storeUpdate() 892 } 893 894 return nil 895} 896 897func (sb *sandbox) clearNetworkResources(origEp *endpoint) error { 898 ep := sb.getEndpoint(origEp.id) 899 if ep == nil { 900 return fmt.Errorf("could not find the sandbox endpoint data for endpoint %s", 901 origEp.id) 902 } 903 904 sb.Lock() 905 osSbox := sb.osSbox 906 inDelete := sb.inDelete 907 sb.Unlock() 908 if osSbox != nil { 909 releaseOSSboxResources(osSbox, ep) 910 } 911 912 sb.Lock() 913 delete(sb.populatedEndpoints, ep.ID()) 914 915 if len(sb.endpoints) == 0 { 916 // sb.endpoints should never be empty and this is unexpected error condition 917 // We log an error message to note this down for debugging purposes. 918 logrus.Errorf("No endpoints in sandbox while trying to remove endpoint %s", ep.Name()) 919 sb.Unlock() 920 return nil 921 } 922 923 var ( 924 gwepBefore, gwepAfter *endpoint 925 index = -1 926 ) 927 for i, e := range sb.endpoints { 928 if e == ep { 929 index = i 930 } 931 if len(e.Gateway()) > 0 && gwepBefore == nil { 932 gwepBefore = e 933 } 934 if index != -1 && gwepBefore != nil { 935 break 936 } 937 } 938 939 if index == -1 { 940 logrus.Warnf("Endpoint %s has already been deleted", ep.Name()) 941 sb.Unlock() 942 return nil 943 } 944 945 sb.removeEndpointRaw(ep) 946 for _, e := range sb.endpoints { 947 if len(e.Gateway()) > 0 { 948 gwepAfter = e 949 break 950 } 951 } 952 delete(sb.epPriority, ep.ID()) 953 sb.Unlock() 954 955 if gwepAfter != nil && gwepBefore != gwepAfter { 956 sb.updateGateway(gwepAfter) 957 } 958 959 // Only update the store if we did not come here as part of 960 // sandbox delete. If we came here as part of delete then do 961 // not bother updating the store. The sandbox object will be 962 // deleted anyway 963 if !inDelete { 964 return sb.storeUpdate() 965 } 966 967 return nil 968} 969 970func (sb *sandbox) isEndpointPopulated(ep *endpoint) bool { 971 sb.Lock() 972 _, ok := sb.populatedEndpoints[ep.ID()] 973 sb.Unlock() 974 return ok 975} 976 977// joinLeaveStart waits to ensure there are no joins or leaves in progress and 978// marks this join/leave in progress without race 979func (sb *sandbox) joinLeaveStart() { 980 sb.Lock() 981 defer sb.Unlock() 982 983 for sb.joinLeaveDone != nil { 984 joinLeaveDone := sb.joinLeaveDone 985 sb.Unlock() 986 987 <-joinLeaveDone 988 989 sb.Lock() 990 } 991 992 sb.joinLeaveDone = make(chan struct{}) 993} 994 995// joinLeaveEnd marks the end of this join/leave operation and 996// signals the same without race to other join and leave waiters 997func (sb *sandbox) joinLeaveEnd() { 998 sb.Lock() 999 defer sb.Unlock() 1000 1001 if sb.joinLeaveDone != nil { 1002 close(sb.joinLeaveDone) 1003 sb.joinLeaveDone = nil 1004 } 1005} 1006 1007func (sb *sandbox) hasPortConfigs() bool { 1008 opts := sb.Labels() 1009 _, hasExpPorts := opts[netlabel.ExposedPorts] 1010 _, hasPortMaps := opts[netlabel.PortMap] 1011 return hasExpPorts || hasPortMaps 1012} 1013 1014// OptionHostname function returns an option setter for hostname option to 1015// be passed to NewSandbox method. 1016func OptionHostname(name string) SandboxOption { 1017 return func(sb *sandbox) { 1018 sb.config.hostName = name 1019 } 1020} 1021 1022// OptionDomainname function returns an option setter for domainname option to 1023// be passed to NewSandbox method. 1024func OptionDomainname(name string) SandboxOption { 1025 return func(sb *sandbox) { 1026 sb.config.domainName = name 1027 } 1028} 1029 1030// OptionHostsPath function returns an option setter for hostspath option to 1031// be passed to NewSandbox method. 1032func OptionHostsPath(path string) SandboxOption { 1033 return func(sb *sandbox) { 1034 sb.config.hostsPath = path 1035 } 1036} 1037 1038// OptionOriginHostsPath function returns an option setter for origin hosts file path 1039// to be passed to NewSandbox method. 1040func OptionOriginHostsPath(path string) SandboxOption { 1041 return func(sb *sandbox) { 1042 sb.config.originHostsPath = path 1043 } 1044} 1045 1046// OptionExtraHost function returns an option setter for extra /etc/hosts options 1047// which is a name and IP as strings. 1048func OptionExtraHost(name string, IP string) SandboxOption { 1049 return func(sb *sandbox) { 1050 sb.config.extraHosts = append(sb.config.extraHosts, extraHost{name: name, IP: IP}) 1051 } 1052} 1053 1054// OptionParentUpdate function returns an option setter for parent container 1055// which needs to update the IP address for the linked container. 1056func OptionParentUpdate(cid string, name, ip string) SandboxOption { 1057 return func(sb *sandbox) { 1058 sb.config.parentUpdates = append(sb.config.parentUpdates, parentUpdate{cid: cid, name: name, ip: ip}) 1059 } 1060} 1061 1062// OptionResolvConfPath function returns an option setter for resolvconfpath option to 1063// be passed to net container methods. 1064func OptionResolvConfPath(path string) SandboxOption { 1065 return func(sb *sandbox) { 1066 sb.config.resolvConfPath = path 1067 } 1068} 1069 1070// OptionOriginResolvConfPath function returns an option setter to set the path to the 1071// origin resolv.conf file to be passed to net container methods. 1072func OptionOriginResolvConfPath(path string) SandboxOption { 1073 return func(sb *sandbox) { 1074 sb.config.originResolvConfPath = path 1075 } 1076} 1077 1078// OptionDNS function returns an option setter for dns entry option to 1079// be passed to container Create method. 1080func OptionDNS(dns string) SandboxOption { 1081 return func(sb *sandbox) { 1082 sb.config.dnsList = append(sb.config.dnsList, dns) 1083 } 1084} 1085 1086// OptionDNSSearch function returns an option setter for dns search entry option to 1087// be passed to container Create method. 1088func OptionDNSSearch(search string) SandboxOption { 1089 return func(sb *sandbox) { 1090 sb.config.dnsSearchList = append(sb.config.dnsSearchList, search) 1091 } 1092} 1093 1094// OptionDNSOptions function returns an option setter for dns options entry option to 1095// be passed to container Create method. 1096func OptionDNSOptions(options string) SandboxOption { 1097 return func(sb *sandbox) { 1098 sb.config.dnsOptionsList = append(sb.config.dnsOptionsList, options) 1099 } 1100} 1101 1102// OptionUseDefaultSandbox function returns an option setter for using default sandbox 1103// (host namespace) to be passed to container Create method. 1104func OptionUseDefaultSandbox() SandboxOption { 1105 return func(sb *sandbox) { 1106 sb.config.useDefaultSandBox = true 1107 } 1108} 1109 1110// OptionUseExternalKey function returns an option setter for using provided namespace 1111// instead of creating one. 1112func OptionUseExternalKey() SandboxOption { 1113 return func(sb *sandbox) { 1114 sb.config.useExternalKey = true 1115 } 1116} 1117 1118// OptionGeneric function returns an option setter for Generic configuration 1119// that is not managed by libNetwork but can be used by the Drivers during the call to 1120// net container creation method. Container Labels are a good example. 1121func OptionGeneric(generic map[string]interface{}) SandboxOption { 1122 return func(sb *sandbox) { 1123 if sb.config.generic == nil { 1124 sb.config.generic = make(map[string]interface{}, len(generic)) 1125 } 1126 for k, v := range generic { 1127 sb.config.generic[k] = v 1128 } 1129 } 1130} 1131 1132// OptionExposedPorts function returns an option setter for the container exposed 1133// ports option to be passed to container Create method. 1134func OptionExposedPorts(exposedPorts []types.TransportPort) SandboxOption { 1135 return func(sb *sandbox) { 1136 if sb.config.generic == nil { 1137 sb.config.generic = make(map[string]interface{}) 1138 } 1139 // Defensive copy 1140 eps := make([]types.TransportPort, len(exposedPorts)) 1141 copy(eps, exposedPorts) 1142 // Store endpoint label and in generic because driver needs it 1143 sb.config.exposedPorts = eps 1144 sb.config.generic[netlabel.ExposedPorts] = eps 1145 } 1146} 1147 1148// OptionPortMapping function returns an option setter for the mapping 1149// ports option to be passed to container Create method. 1150func OptionPortMapping(portBindings []types.PortBinding) SandboxOption { 1151 return func(sb *sandbox) { 1152 if sb.config.generic == nil { 1153 sb.config.generic = make(map[string]interface{}) 1154 } 1155 // Store a copy of the bindings as generic data to pass to the driver 1156 pbs := make([]types.PortBinding, len(portBindings)) 1157 copy(pbs, portBindings) 1158 sb.config.generic[netlabel.PortMap] = pbs 1159 } 1160} 1161 1162// OptionIngress function returns an option setter for marking a 1163// sandbox as the controller's ingress sandbox. 1164func OptionIngress() SandboxOption { 1165 return func(sb *sandbox) { 1166 sb.ingress = true 1167 sb.oslTypes = append(sb.oslTypes, osl.SandboxTypeIngress) 1168 } 1169} 1170 1171// OptionLoadBalancer function returns an option setter for marking a 1172// sandbox as a load balancer sandbox. 1173func OptionLoadBalancer(nid string) SandboxOption { 1174 return func(sb *sandbox) { 1175 sb.loadBalancerNID = nid 1176 sb.oslTypes = append(sb.oslTypes, osl.SandboxTypeLoadBalancer) 1177 } 1178} 1179 1180// <=> Returns true if a < b, false if a > b and advances to next level if a == b 1181// epi.prio <=> epj.prio # 2 < 1 1182// epi.gw <=> epj.gw # non-gw < gw 1183// epi.internal <=> epj.internal # non-internal < internal 1184// epi.joininfo <=> epj.joininfo # ipv6 < ipv4 1185// epi.name <=> epj.name # bar < foo 1186func (epi *endpoint) Less(epj *endpoint) bool { 1187 var ( 1188 prioi, prioj int 1189 ) 1190 1191 sbi, _ := epi.getSandbox() 1192 sbj, _ := epj.getSandbox() 1193 1194 // Prio defaults to 0 1195 if sbi != nil { 1196 prioi = sbi.epPriority[epi.ID()] 1197 } 1198 if sbj != nil { 1199 prioj = sbj.epPriority[epj.ID()] 1200 } 1201 1202 if prioi != prioj { 1203 return prioi > prioj 1204 } 1205 1206 gwi := epi.endpointInGWNetwork() 1207 gwj := epj.endpointInGWNetwork() 1208 if gwi != gwj { 1209 return gwj 1210 } 1211 1212 inti := epi.getNetwork().Internal() 1213 intj := epj.getNetwork().Internal() 1214 if inti != intj { 1215 return intj 1216 } 1217 1218 jii := 0 1219 if epi.joinInfo != nil { 1220 if epi.joinInfo.gw != nil { 1221 jii = jii + 1 1222 } 1223 if epi.joinInfo.gw6 != nil { 1224 jii = jii + 2 1225 } 1226 } 1227 1228 jij := 0 1229 if epj.joinInfo != nil { 1230 if epj.joinInfo.gw != nil { 1231 jij = jij + 1 1232 } 1233 if epj.joinInfo.gw6 != nil { 1234 jij = jij + 2 1235 } 1236 } 1237 1238 if jii != jij { 1239 return jii > jij 1240 } 1241 1242 return epi.network.Name() < epj.network.Name() 1243} 1244 1245func (sb *sandbox) NdotsSet() bool { 1246 return sb.ndotsSet 1247} 1248