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