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