Browse code

Move network operations out of container package

These network operations really don't have anything to do with the
container but rather are setting up the networking.

Ideally these wouldn't get shoved into the daemon package, but doing
something else (e.g. extract a network service into a new package) but
there's a lot more work to do in that regard.
In reality, this probably simplifies some of that work as it moves all
the network operations to the same place.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>

Brian Goff authored on 2018/05/11 05:44:09
Showing 5 changed files
... ...
@@ -6,11 +6,9 @@ import (
6 6
 	"encoding/json"
7 7
 	"fmt"
8 8
 	"io"
9
-	"net"
10 9
 	"os"
11 10
 	"path/filepath"
12 11
 	"runtime"
13
-	"strconv"
14 12
 	"strings"
15 13
 	"sync"
16 14
 	"syscall"
... ...
@@ -19,7 +17,6 @@ import (
19 19
 	"github.com/containerd/containerd/cio"
20 20
 	containertypes "github.com/docker/docker/api/types/container"
21 21
 	mounttypes "github.com/docker/docker/api/types/mount"
22
-	networktypes "github.com/docker/docker/api/types/network"
23 22
 	swarmtypes "github.com/docker/docker/api/types/swarm"
24 23
 	"github.com/docker/docker/container/stream"
25 24
 	"github.com/docker/docker/daemon/exec"
... ...
@@ -28,7 +25,6 @@ import (
28 28
 	"github.com/docker/docker/daemon/network"
29 29
 	"github.com/docker/docker/image"
30 30
 	"github.com/docker/docker/layer"
31
-	"github.com/docker/docker/opts"
32 31
 	"github.com/docker/docker/pkg/containerfs"
33 32
 	"github.com/docker/docker/pkg/idtools"
34 33
 	"github.com/docker/docker/pkg/ioutils"
... ...
@@ -36,15 +32,9 @@ import (
36 36
 	"github.com/docker/docker/pkg/symlink"
37 37
 	"github.com/docker/docker/pkg/system"
38 38
 	"github.com/docker/docker/restartmanager"
39
-	"github.com/docker/docker/runconfig"
40 39
 	"github.com/docker/docker/volume"
41 40
 	volumemounts "github.com/docker/docker/volume/mounts"
42
-	"github.com/docker/go-connections/nat"
43
-	units "github.com/docker/go-units"
44
-	"github.com/docker/libnetwork"
45
-	"github.com/docker/libnetwork/netlabel"
46
-	"github.com/docker/libnetwork/options"
47
-	"github.com/docker/libnetwork/types"
41
+	"github.com/docker/go-units"
48 42
 	agentexec "github.com/docker/swarmkit/agent/exec"
49 43
 	"github.com/pkg/errors"
50 44
 	"github.com/sirupsen/logrus"
... ...
@@ -52,11 +42,6 @@ import (
52 52
 
53 53
 const configFileName = "config.v2.json"
54 54
 
55
-var (
56
-	errInvalidEndpoint = errors.New("invalid endpoint while building port map info")
57
-	errInvalidNetwork  = errors.New("invalid network settings while building port map info")
58
-)
59
-
60 55
 // ExitStatus provides exit reasons for a container.
61 56
 type ExitStatus struct {
62 57
 	// The exit code with which the container exited.
... ...
@@ -538,366 +523,6 @@ func (container *Container) InitDNSHostConfig() {
538 538
 	}
539 539
 }
540 540
 
541
-// GetEndpointInNetwork returns the container's endpoint to the provided network.
542
-func (container *Container) GetEndpointInNetwork(n libnetwork.Network) (libnetwork.Endpoint, error) {
543
-	endpointName := strings.TrimPrefix(container.Name, "/")
544
-	return n.EndpointByName(endpointName)
545
-}
546
-
547
-func (container *Container) buildPortMapInfo(ep libnetwork.Endpoint) error {
548
-	if ep == nil {
549
-		return errInvalidEndpoint
550
-	}
551
-
552
-	networkSettings := container.NetworkSettings
553
-	if networkSettings == nil {
554
-		return errInvalidNetwork
555
-	}
556
-
557
-	if len(networkSettings.Ports) == 0 {
558
-		pm, err := getEndpointPortMapInfo(ep)
559
-		if err != nil {
560
-			return err
561
-		}
562
-		networkSettings.Ports = pm
563
-	}
564
-	return nil
565
-}
566
-
567
-func getEndpointPortMapInfo(ep libnetwork.Endpoint) (nat.PortMap, error) {
568
-	pm := nat.PortMap{}
569
-	driverInfo, err := ep.DriverInfo()
570
-	if err != nil {
571
-		return pm, err
572
-	}
573
-
574
-	if driverInfo == nil {
575
-		// It is not an error for epInfo to be nil
576
-		return pm, nil
577
-	}
578
-
579
-	if expData, ok := driverInfo[netlabel.ExposedPorts]; ok {
580
-		if exposedPorts, ok := expData.([]types.TransportPort); ok {
581
-			for _, tp := range exposedPorts {
582
-				natPort, err := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port)))
583
-				if err != nil {
584
-					return pm, fmt.Errorf("Error parsing Port value(%v):%v", tp.Port, err)
585
-				}
586
-				pm[natPort] = nil
587
-			}
588
-		}
589
-	}
590
-
591
-	mapData, ok := driverInfo[netlabel.PortMap]
592
-	if !ok {
593
-		return pm, nil
594
-	}
595
-
596
-	if portMapping, ok := mapData.([]types.PortBinding); ok {
597
-		for _, pp := range portMapping {
598
-			natPort, err := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port)))
599
-			if err != nil {
600
-				return pm, err
601
-			}
602
-			natBndg := nat.PortBinding{HostIP: pp.HostIP.String(), HostPort: strconv.Itoa(int(pp.HostPort))}
603
-			pm[natPort] = append(pm[natPort], natBndg)
604
-		}
605
-	}
606
-
607
-	return pm, nil
608
-}
609
-
610
-// GetSandboxPortMapInfo retrieves the current port-mapping programmed for the given sandbox
611
-func GetSandboxPortMapInfo(sb libnetwork.Sandbox) nat.PortMap {
612
-	pm := nat.PortMap{}
613
-	if sb == nil {
614
-		return pm
615
-	}
616
-
617
-	for _, ep := range sb.Endpoints() {
618
-		pm, _ = getEndpointPortMapInfo(ep)
619
-		if len(pm) > 0 {
620
-			break
621
-		}
622
-	}
623
-	return pm
624
-}
625
-
626
-// BuildEndpointInfo sets endpoint-related fields on container.NetworkSettings based on the provided network and endpoint.
627
-func (container *Container) BuildEndpointInfo(n libnetwork.Network, ep libnetwork.Endpoint) error {
628
-	if ep == nil {
629
-		return errInvalidEndpoint
630
-	}
631
-
632
-	networkSettings := container.NetworkSettings
633
-	if networkSettings == nil {
634
-		return errInvalidNetwork
635
-	}
636
-
637
-	epInfo := ep.Info()
638
-	if epInfo == nil {
639
-		// It is not an error to get an empty endpoint info
640
-		return nil
641
-	}
642
-
643
-	if _, ok := networkSettings.Networks[n.Name()]; !ok {
644
-		networkSettings.Networks[n.Name()] = &network.EndpointSettings{
645
-			EndpointSettings: &networktypes.EndpointSettings{},
646
-		}
647
-	}
648
-	networkSettings.Networks[n.Name()].NetworkID = n.ID()
649
-	networkSettings.Networks[n.Name()].EndpointID = ep.ID()
650
-
651
-	iface := epInfo.Iface()
652
-	if iface == nil {
653
-		return nil
654
-	}
655
-
656
-	if iface.MacAddress() != nil {
657
-		networkSettings.Networks[n.Name()].MacAddress = iface.MacAddress().String()
658
-	}
659
-
660
-	if iface.Address() != nil {
661
-		ones, _ := iface.Address().Mask.Size()
662
-		networkSettings.Networks[n.Name()].IPAddress = iface.Address().IP.String()
663
-		networkSettings.Networks[n.Name()].IPPrefixLen = ones
664
-	}
665
-
666
-	if iface.AddressIPv6() != nil && iface.AddressIPv6().IP.To16() != nil {
667
-		onesv6, _ := iface.AddressIPv6().Mask.Size()
668
-		networkSettings.Networks[n.Name()].GlobalIPv6Address = iface.AddressIPv6().IP.String()
669
-		networkSettings.Networks[n.Name()].GlobalIPv6PrefixLen = onesv6
670
-	}
671
-
672
-	return nil
673
-}
674
-
675
-type named interface {
676
-	Name() string
677
-}
678
-
679
-// UpdateJoinInfo updates network settings when container joins network n with endpoint ep.
680
-func (container *Container) UpdateJoinInfo(n named, ep libnetwork.Endpoint) error {
681
-	if err := container.buildPortMapInfo(ep); err != nil {
682
-		return err
683
-	}
684
-
685
-	epInfo := ep.Info()
686
-	if epInfo == nil {
687
-		// It is not an error to get an empty endpoint info
688
-		return nil
689
-	}
690
-	if epInfo.Gateway() != nil {
691
-		container.NetworkSettings.Networks[n.Name()].Gateway = epInfo.Gateway().String()
692
-	}
693
-	if epInfo.GatewayIPv6().To16() != nil {
694
-		container.NetworkSettings.Networks[n.Name()].IPv6Gateway = epInfo.GatewayIPv6().String()
695
-	}
696
-
697
-	return nil
698
-}
699
-
700
-// UpdateSandboxNetworkSettings updates the sandbox ID and Key.
701
-func (container *Container) UpdateSandboxNetworkSettings(sb libnetwork.Sandbox) error {
702
-	container.NetworkSettings.SandboxID = sb.ID()
703
-	container.NetworkSettings.SandboxKey = sb.Key()
704
-	return nil
705
-}
706
-
707
-// BuildJoinOptions builds endpoint Join options from a given network.
708
-func (container *Container) BuildJoinOptions(n named) ([]libnetwork.EndpointOption, error) {
709
-	var joinOptions []libnetwork.EndpointOption
710
-	if epConfig, ok := container.NetworkSettings.Networks[n.Name()]; ok {
711
-		for _, str := range epConfig.Links {
712
-			name, alias, err := opts.ParseLink(str)
713
-			if err != nil {
714
-				return nil, err
715
-			}
716
-			joinOptions = append(joinOptions, libnetwork.CreateOptionAlias(name, alias))
717
-		}
718
-		for k, v := range epConfig.DriverOpts {
719
-			joinOptions = append(joinOptions, libnetwork.EndpointOptionGeneric(options.Generic{k: v}))
720
-		}
721
-	}
722
-
723
-	return joinOptions, nil
724
-}
725
-
726
-// BuildCreateEndpointOptions builds endpoint options from a given network.
727
-func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network, epConfig *networktypes.EndpointSettings, sb libnetwork.Sandbox, daemonDNS []string) ([]libnetwork.EndpointOption, error) {
728
-	var (
729
-		bindings      = make(nat.PortMap)
730
-		pbList        []types.PortBinding
731
-		exposeList    []types.TransportPort
732
-		createOptions []libnetwork.EndpointOption
733
-	)
734
-
735
-	defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName()
736
-
737
-	if (!container.EnableServiceDiscoveryOnDefaultNetwork() && n.Name() == defaultNetName) ||
738
-		container.NetworkSettings.IsAnonymousEndpoint {
739
-		createOptions = append(createOptions, libnetwork.CreateOptionAnonymous())
740
-	}
741
-
742
-	if epConfig != nil {
743
-		ipam := epConfig.IPAMConfig
744
-
745
-		if ipam != nil {
746
-			var (
747
-				ipList          []net.IP
748
-				ip, ip6, linkip net.IP
749
-			)
750
-
751
-			for _, ips := range ipam.LinkLocalIPs {
752
-				if linkip = net.ParseIP(ips); linkip == nil && ips != "" {
753
-					return nil, errors.Errorf("Invalid link-local IP address: %s", ipam.LinkLocalIPs)
754
-				}
755
-				ipList = append(ipList, linkip)
756
-
757
-			}
758
-
759
-			if ip = net.ParseIP(ipam.IPv4Address); ip == nil && ipam.IPv4Address != "" {
760
-				return nil, errors.Errorf("Invalid IPv4 address: %s)", ipam.IPv4Address)
761
-			}
762
-
763
-			if ip6 = net.ParseIP(ipam.IPv6Address); ip6 == nil && ipam.IPv6Address != "" {
764
-				return nil, errors.Errorf("Invalid IPv6 address: %s)", ipam.IPv6Address)
765
-			}
766
-
767
-			createOptions = append(createOptions,
768
-				libnetwork.CreateOptionIpam(ip, ip6, ipList, nil))
769
-
770
-		}
771
-
772
-		for _, alias := range epConfig.Aliases {
773
-			createOptions = append(createOptions, libnetwork.CreateOptionMyAlias(alias))
774
-		}
775
-		for k, v := range epConfig.DriverOpts {
776
-			createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(options.Generic{k: v}))
777
-		}
778
-	}
779
-
780
-	if container.NetworkSettings.Service != nil {
781
-		svcCfg := container.NetworkSettings.Service
782
-
783
-		var vip string
784
-		if svcCfg.VirtualAddresses[n.ID()] != nil {
785
-			vip = svcCfg.VirtualAddresses[n.ID()].IPv4
786
-		}
787
-
788
-		var portConfigs []*libnetwork.PortConfig
789
-		for _, portConfig := range svcCfg.ExposedPorts {
790
-			portConfigs = append(portConfigs, &libnetwork.PortConfig{
791
-				Name:          portConfig.Name,
792
-				Protocol:      libnetwork.PortConfig_Protocol(portConfig.Protocol),
793
-				TargetPort:    portConfig.TargetPort,
794
-				PublishedPort: portConfig.PublishedPort,
795
-			})
796
-		}
797
-
798
-		createOptions = append(createOptions, libnetwork.CreateOptionService(svcCfg.Name, svcCfg.ID, net.ParseIP(vip), portConfigs, svcCfg.Aliases[n.ID()]))
799
-	}
800
-
801
-	if !containertypes.NetworkMode(n.Name()).IsUserDefined() {
802
-		createOptions = append(createOptions, libnetwork.CreateOptionDisableResolution())
803
-	}
804
-
805
-	// configs that are applicable only for the endpoint in the network
806
-	// to which container was connected to on docker run.
807
-	// Ideally all these network-specific endpoint configurations must be moved under
808
-	// container.NetworkSettings.Networks[n.Name()]
809
-	if n.Name() == container.HostConfig.NetworkMode.NetworkName() ||
810
-		(n.Name() == defaultNetName && container.HostConfig.NetworkMode.IsDefault()) {
811
-		if container.Config.MacAddress != "" {
812
-			mac, err := net.ParseMAC(container.Config.MacAddress)
813
-			if err != nil {
814
-				return nil, err
815
-			}
816
-
817
-			genericOption := options.Generic{
818
-				netlabel.MacAddress: mac,
819
-			}
820
-
821
-			createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption))
822
-		}
823
-
824
-	}
825
-
826
-	// Port-mapping rules belong to the container & applicable only to non-internal networks
827
-	portmaps := GetSandboxPortMapInfo(sb)
828
-	if n.Info().Internal() || len(portmaps) > 0 {
829
-		return createOptions, nil
830
-	}
831
-
832
-	if container.HostConfig.PortBindings != nil {
833
-		for p, b := range container.HostConfig.PortBindings {
834
-			bindings[p] = []nat.PortBinding{}
835
-			for _, bb := range b {
836
-				bindings[p] = append(bindings[p], nat.PortBinding{
837
-					HostIP:   bb.HostIP,
838
-					HostPort: bb.HostPort,
839
-				})
840
-			}
841
-		}
842
-	}
843
-
844
-	portSpecs := container.Config.ExposedPorts
845
-	ports := make([]nat.Port, len(portSpecs))
846
-	var i int
847
-	for p := range portSpecs {
848
-		ports[i] = p
849
-		i++
850
-	}
851
-	nat.SortPortMap(ports, bindings)
852
-	for _, port := range ports {
853
-		expose := types.TransportPort{}
854
-		expose.Proto = types.ParseProtocol(port.Proto())
855
-		expose.Port = uint16(port.Int())
856
-		exposeList = append(exposeList, expose)
857
-
858
-		pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto}
859
-		binding := bindings[port]
860
-		for i := 0; i < len(binding); i++ {
861
-			pbCopy := pb.GetCopy()
862
-			newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort))
863
-			var portStart, portEnd int
864
-			if err == nil {
865
-				portStart, portEnd, err = newP.Range()
866
-			}
867
-			if err != nil {
868
-				return nil, errors.Wrapf(err, "Error parsing HostPort value (%s)", binding[i].HostPort)
869
-			}
870
-			pbCopy.HostPort = uint16(portStart)
871
-			pbCopy.HostPortEnd = uint16(portEnd)
872
-			pbCopy.HostIP = net.ParseIP(binding[i].HostIP)
873
-			pbList = append(pbList, pbCopy)
874
-		}
875
-
876
-		if container.HostConfig.PublishAllPorts && len(binding) == 0 {
877
-			pbList = append(pbList, pb)
878
-		}
879
-	}
880
-
881
-	var dns []string
882
-
883
-	if len(container.HostConfig.DNS) > 0 {
884
-		dns = container.HostConfig.DNS
885
-	} else if len(daemonDNS) > 0 {
886
-		dns = daemonDNS
887
-	}
888
-
889
-	if len(dns) > 0 {
890
-		createOptions = append(createOptions,
891
-			libnetwork.CreateOptionDNS(dns))
892
-	}
893
-
894
-	createOptions = append(createOptions,
895
-		libnetwork.CreateOptionPortMapping(pbList),
896
-		libnetwork.CreateOptionExposedPorts(exposeList))
897
-
898
-	return createOptions, nil
899
-}
900
-
901 541
 // UpdateMonitor updates monitor configure for running container
902 542
 func (container *Container) UpdateMonitor(restartPolicy containertypes.RestartPolicy) {
903 543
 	type policySetter interface {
... ...
@@ -31,7 +31,7 @@ var (
31 31
 	// ErrRootFSReadOnly is returned when a container
32 32
 	// rootfs is marked readonly.
33 33
 	ErrRootFSReadOnly = errors.New("container rootfs is marked read-only")
34
-	getPortMapInfo    = container.GetSandboxPortMapInfo
34
+	getPortMapInfo    = getSandboxPortMapInfo
35 35
 )
36 36
 
37 37
 func (daemon *Daemon) getDNSSearchSettings(container *container.Container) []string {
... ...
@@ -288,7 +288,7 @@ func (daemon *Daemon) updateNetworkSettings(container *container.Container, n li
288 288
 }
289 289
 
290 290
 func (daemon *Daemon) updateEndpointNetworkSettings(container *container.Container, n libnetwork.Network, ep libnetwork.Endpoint) error {
291
-	if err := container.BuildEndpointInfo(n, ep); err != nil {
291
+	if err := buildEndpointInfo(container.NetworkSettings, n, ep); err != nil {
292 292
 		return err
293 293
 	}
294 294
 
... ...
@@ -572,7 +572,7 @@ func (daemon *Daemon) allocateNetwork(container *container.Container) error {
572 572
 			if err != nil {
573 573
 				return err
574 574
 			}
575
-			container.UpdateSandboxNetworkSettings(sb)
575
+			updateSandboxNetworkSettings(container, sb)
576 576
 			defer func() {
577 577
 				if err != nil {
578 578
 					sb.Delete()
... ...
@@ -740,7 +740,7 @@ func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName
740 740
 
741 741
 	controller := daemon.netController
742 742
 	sb := daemon.getNetworkSandbox(container)
743
-	createOptions, err := container.BuildCreateEndpointOptions(n, endpointConfig, sb, daemon.configStore.DNS)
743
+	createOptions, err := buildCreateEndpointOptions(container, n, endpointConfig, sb, daemon.configStore.DNS)
744 744
 	if err != nil {
745 745
 		return err
746 746
 	}
... ...
@@ -779,10 +779,10 @@ func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName
779 779
 			return err
780 780
 		}
781 781
 
782
-		container.UpdateSandboxNetworkSettings(sb)
782
+		updateSandboxNetworkSettings(container, sb)
783 783
 	}
784 784
 
785
-	joinOptions, err := container.BuildJoinOptions(n)
785
+	joinOptions, err := buildJoinOptions(container.NetworkSettings, n)
786 786
 	if err != nil {
787 787
 		return err
788 788
 	}
... ...
@@ -798,7 +798,7 @@ func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName
798 798
 		}
799 799
 	}
800 800
 
801
-	if err := container.UpdateJoinInfo(n, ep); err != nil {
801
+	if err := updateJoinInfo(container.NetworkSettings, n, ep); err != nil {
802 802
 		return fmt.Errorf("Updating join info failed: %v", err)
803 803
 	}
804 804
 
... ...
@@ -809,6 +809,37 @@ func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName
809 809
 	return nil
810 810
 }
811 811
 
812
+func updateJoinInfo(networkSettings *network.Settings, n libnetwork.Network, ep libnetwork.Endpoint) error { // nolint: interfacer
813
+	if ep == nil {
814
+		return errors.New("invalid enppoint whhile building portmap info")
815
+	}
816
+
817
+	if networkSettings == nil {
818
+		return errors.New("invalid network settings while building port map info")
819
+	}
820
+
821
+	if len(networkSettings.Ports) == 0 {
822
+		pm, err := getEndpointPortMapInfo(ep)
823
+		if err != nil {
824
+			return err
825
+		}
826
+		networkSettings.Ports = pm
827
+	}
828
+
829
+	epInfo := ep.Info()
830
+	if epInfo == nil {
831
+		// It is not an error to get an empty endpoint info
832
+		return nil
833
+	}
834
+	if epInfo.Gateway() != nil {
835
+		networkSettings.Networks[n.Name()].Gateway = epInfo.Gateway().String()
836
+	}
837
+	if epInfo.GatewayIPv6().To16() != nil {
838
+		networkSettings.Networks[n.Name()].IPv6Gateway = epInfo.GatewayIPv6().String()
839
+	}
840
+	return nil
841
+}
842
+
812 843
 // ForceEndpointDelete deletes an endpoint from a network forcefully
813 844
 func (daemon *Daemon) ForceEndpointDelete(name string, networkName string) error {
814 845
 	n, err := daemon.FindNetwork(networkName)
... ...
@@ -1110,3 +1141,10 @@ func getNetworkID(name string, endpointSettings *networktypes.EndpointSettings)
1110 1110
 	}
1111 1111
 	return name
1112 1112
 }
1113
+
1114
+// updateSandboxNetworkSettings updates the sandbox ID and Key.
1115
+func updateSandboxNetworkSettings(c *container.Container, sb libnetwork.Sandbox) error {
1116
+	c.NetworkSettings.SandboxID = sb.ID()
1117
+	c.NetworkSettings.SandboxKey = sb.Key()
1118
+	return nil
1119
+}
... ...
@@ -174,7 +174,7 @@ func (daemon *Daemon) initializeNetworkingPaths(container *container.Container,
174 174
 				continue
175 175
 			}
176 176
 
177
-			ep, err := nc.GetEndpointInNetwork(sn)
177
+			ep, err := getEndpointInNetwork(nc.Name, sn)
178 178
 			if err != nil {
179 179
 				continue
180 180
 			}
... ...
@@ -6,19 +6,27 @@ import (
6 6
 	"net"
7 7
 	"runtime"
8 8
 	"sort"
9
+	"strconv"
9 10
 	"strings"
10 11
 	"sync"
11 12
 
12 13
 	"github.com/docker/docker/api/types"
14
+	containertypes "github.com/docker/docker/api/types/container"
13 15
 	"github.com/docker/docker/api/types/network"
16
+	"github.com/docker/docker/container"
14 17
 	clustertypes "github.com/docker/docker/daemon/cluster/provider"
18
+	internalnetwork "github.com/docker/docker/daemon/network"
15 19
 	"github.com/docker/docker/errdefs"
20
+	"github.com/docker/docker/opts"
16 21
 	"github.com/docker/docker/pkg/plugingetter"
17 22
 	"github.com/docker/docker/runconfig"
23
+	"github.com/docker/go-connections/nat"
18 24
 	"github.com/docker/libnetwork"
19 25
 	lncluster "github.com/docker/libnetwork/cluster"
20 26
 	"github.com/docker/libnetwork/driverapi"
21 27
 	"github.com/docker/libnetwork/ipamapi"
28
+	"github.com/docker/libnetwork/netlabel"
29
+	"github.com/docker/libnetwork/options"
22 30
 	networktypes "github.com/docker/libnetwork/types"
23 31
 	"github.com/pkg/errors"
24 32
 	"github.com/sirupsen/logrus"
... ...
@@ -48,7 +56,7 @@ func (daemon *Daemon) NetworkControllerEnabled() bool {
48 48
 func (daemon *Daemon) FindNetwork(term string) (libnetwork.Network, error) {
49 49
 	listByFullName := []libnetwork.Network{}
50 50
 	listByPartialID := []libnetwork.Network{}
51
-	for _, nw := range daemon.GetNetworks() {
51
+	for _, nw := range daemon.getAllNetworks() {
52 52
 		if nw.ID() == term {
53 53
 			return nw, nil
54 54
 		}
... ...
@@ -575,7 +583,7 @@ func (daemon *Daemon) GetNetworks() []libnetwork.Network {
575 575
 // clearAttachableNetworks removes the attachable networks
576 576
 // after disconnecting any connected container
577 577
 func (daemon *Daemon) clearAttachableNetworks() {
578
-	for _, n := range daemon.GetNetworks() {
578
+	for _, n := range daemon.getAllNetworks() {
579 579
 		if !n.Info().Attachable() {
580 580
 			continue
581 581
 		}
... ...
@@ -599,3 +607,312 @@ func (daemon *Daemon) clearAttachableNetworks() {
599 599
 		}
600 600
 	}
601 601
 }
602
+
603
+// buildCreateEndpointOptions builds endpoint options from a given network.
604
+func buildCreateEndpointOptions(c *container.Container, n libnetwork.Network, epConfig *network.EndpointSettings, sb libnetwork.Sandbox, daemonDNS []string) ([]libnetwork.EndpointOption, error) {
605
+	var (
606
+		bindings      = make(nat.PortMap)
607
+		pbList        []networktypes.PortBinding
608
+		exposeList    []networktypes.TransportPort
609
+		createOptions []libnetwork.EndpointOption
610
+	)
611
+
612
+	defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName()
613
+
614
+	if (!c.EnableServiceDiscoveryOnDefaultNetwork() && n.Name() == defaultNetName) ||
615
+		c.NetworkSettings.IsAnonymousEndpoint {
616
+		createOptions = append(createOptions, libnetwork.CreateOptionAnonymous())
617
+	}
618
+
619
+	if epConfig != nil {
620
+		ipam := epConfig.IPAMConfig
621
+
622
+		if ipam != nil {
623
+			var (
624
+				ipList          []net.IP
625
+				ip, ip6, linkip net.IP
626
+			)
627
+
628
+			for _, ips := range ipam.LinkLocalIPs {
629
+				if linkip = net.ParseIP(ips); linkip == nil && ips != "" {
630
+					return nil, errors.Errorf("Invalid link-local IP address: %s", ipam.LinkLocalIPs)
631
+				}
632
+				ipList = append(ipList, linkip)
633
+
634
+			}
635
+
636
+			if ip = net.ParseIP(ipam.IPv4Address); ip == nil && ipam.IPv4Address != "" {
637
+				return nil, errors.Errorf("Invalid IPv4 address: %s)", ipam.IPv4Address)
638
+			}
639
+
640
+			if ip6 = net.ParseIP(ipam.IPv6Address); ip6 == nil && ipam.IPv6Address != "" {
641
+				return nil, errors.Errorf("Invalid IPv6 address: %s)", ipam.IPv6Address)
642
+			}
643
+
644
+			createOptions = append(createOptions,
645
+				libnetwork.CreateOptionIpam(ip, ip6, ipList, nil))
646
+
647
+		}
648
+
649
+		for _, alias := range epConfig.Aliases {
650
+			createOptions = append(createOptions, libnetwork.CreateOptionMyAlias(alias))
651
+		}
652
+		for k, v := range epConfig.DriverOpts {
653
+			createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(options.Generic{k: v}))
654
+		}
655
+	}
656
+
657
+	if c.NetworkSettings.Service != nil {
658
+		svcCfg := c.NetworkSettings.Service
659
+
660
+		var vip string
661
+		if svcCfg.VirtualAddresses[n.ID()] != nil {
662
+			vip = svcCfg.VirtualAddresses[n.ID()].IPv4
663
+		}
664
+
665
+		var portConfigs []*libnetwork.PortConfig
666
+		for _, portConfig := range svcCfg.ExposedPorts {
667
+			portConfigs = append(portConfigs, &libnetwork.PortConfig{
668
+				Name:          portConfig.Name,
669
+				Protocol:      libnetwork.PortConfig_Protocol(portConfig.Protocol),
670
+				TargetPort:    portConfig.TargetPort,
671
+				PublishedPort: portConfig.PublishedPort,
672
+			})
673
+		}
674
+
675
+		createOptions = append(createOptions, libnetwork.CreateOptionService(svcCfg.Name, svcCfg.ID, net.ParseIP(vip), portConfigs, svcCfg.Aliases[n.ID()]))
676
+	}
677
+
678
+	if !containertypes.NetworkMode(n.Name()).IsUserDefined() {
679
+		createOptions = append(createOptions, libnetwork.CreateOptionDisableResolution())
680
+	}
681
+
682
+	// configs that are applicable only for the endpoint in the network
683
+	// to which container was connected to on docker run.
684
+	// Ideally all these network-specific endpoint configurations must be moved under
685
+	// container.NetworkSettings.Networks[n.Name()]
686
+	if n.Name() == c.HostConfig.NetworkMode.NetworkName() ||
687
+		(n.Name() == defaultNetName && c.HostConfig.NetworkMode.IsDefault()) {
688
+		if c.Config.MacAddress != "" {
689
+			mac, err := net.ParseMAC(c.Config.MacAddress)
690
+			if err != nil {
691
+				return nil, err
692
+			}
693
+
694
+			genericOption := options.Generic{
695
+				netlabel.MacAddress: mac,
696
+			}
697
+
698
+			createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption))
699
+		}
700
+
701
+	}
702
+
703
+	// Port-mapping rules belong to the container & applicable only to non-internal networks
704
+	portmaps := getSandboxPortMapInfo(sb)
705
+	if n.Info().Internal() || len(portmaps) > 0 {
706
+		return createOptions, nil
707
+	}
708
+
709
+	if c.HostConfig.PortBindings != nil {
710
+		for p, b := range c.HostConfig.PortBindings {
711
+			bindings[p] = []nat.PortBinding{}
712
+			for _, bb := range b {
713
+				bindings[p] = append(bindings[p], nat.PortBinding{
714
+					HostIP:   bb.HostIP,
715
+					HostPort: bb.HostPort,
716
+				})
717
+			}
718
+		}
719
+	}
720
+
721
+	portSpecs := c.Config.ExposedPorts
722
+	ports := make([]nat.Port, len(portSpecs))
723
+	var i int
724
+	for p := range portSpecs {
725
+		ports[i] = p
726
+		i++
727
+	}
728
+	nat.SortPortMap(ports, bindings)
729
+	for _, port := range ports {
730
+		expose := networktypes.TransportPort{}
731
+		expose.Proto = networktypes.ParseProtocol(port.Proto())
732
+		expose.Port = uint16(port.Int())
733
+		exposeList = append(exposeList, expose)
734
+
735
+		pb := networktypes.PortBinding{Port: expose.Port, Proto: expose.Proto}
736
+		binding := bindings[port]
737
+		for i := 0; i < len(binding); i++ {
738
+			pbCopy := pb.GetCopy()
739
+			newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort))
740
+			var portStart, portEnd int
741
+			if err == nil {
742
+				portStart, portEnd, err = newP.Range()
743
+			}
744
+			if err != nil {
745
+				return nil, errors.Wrapf(err, "Error parsing HostPort value (%s)", binding[i].HostPort)
746
+			}
747
+			pbCopy.HostPort = uint16(portStart)
748
+			pbCopy.HostPortEnd = uint16(portEnd)
749
+			pbCopy.HostIP = net.ParseIP(binding[i].HostIP)
750
+			pbList = append(pbList, pbCopy)
751
+		}
752
+
753
+		if c.HostConfig.PublishAllPorts && len(binding) == 0 {
754
+			pbList = append(pbList, pb)
755
+		}
756
+	}
757
+
758
+	var dns []string
759
+
760
+	if len(c.HostConfig.DNS) > 0 {
761
+		dns = c.HostConfig.DNS
762
+	} else if len(daemonDNS) > 0 {
763
+		dns = daemonDNS
764
+	}
765
+
766
+	if len(dns) > 0 {
767
+		createOptions = append(createOptions,
768
+			libnetwork.CreateOptionDNS(dns))
769
+	}
770
+
771
+	createOptions = append(createOptions,
772
+		libnetwork.CreateOptionPortMapping(pbList),
773
+		libnetwork.CreateOptionExposedPorts(exposeList))
774
+
775
+	return createOptions, nil
776
+}
777
+
778
+// getEndpointInNetwork returns the container's endpoint to the provided network.
779
+func getEndpointInNetwork(name string, n libnetwork.Network) (libnetwork.Endpoint, error) {
780
+	endpointName := strings.TrimPrefix(name, "/")
781
+	return n.EndpointByName(endpointName)
782
+}
783
+
784
+// getSandboxPortMapInfo retrieves the current port-mapping programmed for the given sandbox
785
+func getSandboxPortMapInfo(sb libnetwork.Sandbox) nat.PortMap {
786
+	pm := nat.PortMap{}
787
+	if sb == nil {
788
+		return pm
789
+	}
790
+
791
+	for _, ep := range sb.Endpoints() {
792
+		pm, _ = getEndpointPortMapInfo(ep)
793
+		if len(pm) > 0 {
794
+			break
795
+		}
796
+	}
797
+	return pm
798
+}
799
+
800
+func getEndpointPortMapInfo(ep libnetwork.Endpoint) (nat.PortMap, error) {
801
+	pm := nat.PortMap{}
802
+	driverInfo, err := ep.DriverInfo()
803
+	if err != nil {
804
+		return pm, err
805
+	}
806
+
807
+	if driverInfo == nil {
808
+		// It is not an error for epInfo to be nil
809
+		return pm, nil
810
+	}
811
+
812
+	if expData, ok := driverInfo[netlabel.ExposedPorts]; ok {
813
+		if exposedPorts, ok := expData.([]networktypes.TransportPort); ok {
814
+			for _, tp := range exposedPorts {
815
+				natPort, err := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port)))
816
+				if err != nil {
817
+					return pm, fmt.Errorf("Error parsing Port value(%v):%v", tp.Port, err)
818
+				}
819
+				pm[natPort] = nil
820
+			}
821
+		}
822
+	}
823
+
824
+	mapData, ok := driverInfo[netlabel.PortMap]
825
+	if !ok {
826
+		return pm, nil
827
+	}
828
+
829
+	if portMapping, ok := mapData.([]networktypes.PortBinding); ok {
830
+		for _, pp := range portMapping {
831
+			natPort, err := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port)))
832
+			if err != nil {
833
+				return pm, err
834
+			}
835
+			natBndg := nat.PortBinding{HostIP: pp.HostIP.String(), HostPort: strconv.Itoa(int(pp.HostPort))}
836
+			pm[natPort] = append(pm[natPort], natBndg)
837
+		}
838
+	}
839
+
840
+	return pm, nil
841
+}
842
+
843
+// buildEndpointInfo sets endpoint-related fields on container.NetworkSettings based on the provided network and endpoint.
844
+func buildEndpointInfo(networkSettings *internalnetwork.Settings, n libnetwork.Network, ep libnetwork.Endpoint) error {
845
+	if ep == nil {
846
+		return errors.New("endpoint cannot be nil")
847
+	}
848
+
849
+	if networkSettings == nil {
850
+		return errors.New("network cannot be nil")
851
+	}
852
+
853
+	epInfo := ep.Info()
854
+	if epInfo == nil {
855
+		// It is not an error to get an empty endpoint info
856
+		return nil
857
+	}
858
+
859
+	if _, ok := networkSettings.Networks[n.Name()]; !ok {
860
+		networkSettings.Networks[n.Name()] = &internalnetwork.EndpointSettings{
861
+			EndpointSettings: &network.EndpointSettings{},
862
+		}
863
+	}
864
+	networkSettings.Networks[n.Name()].NetworkID = n.ID()
865
+	networkSettings.Networks[n.Name()].EndpointID = ep.ID()
866
+
867
+	iface := epInfo.Iface()
868
+	if iface == nil {
869
+		return nil
870
+	}
871
+
872
+	if iface.MacAddress() != nil {
873
+		networkSettings.Networks[n.Name()].MacAddress = iface.MacAddress().String()
874
+	}
875
+
876
+	if iface.Address() != nil {
877
+		ones, _ := iface.Address().Mask.Size()
878
+		networkSettings.Networks[n.Name()].IPAddress = iface.Address().IP.String()
879
+		networkSettings.Networks[n.Name()].IPPrefixLen = ones
880
+	}
881
+
882
+	if iface.AddressIPv6() != nil && iface.AddressIPv6().IP.To16() != nil {
883
+		onesv6, _ := iface.AddressIPv6().Mask.Size()
884
+		networkSettings.Networks[n.Name()].GlobalIPv6Address = iface.AddressIPv6().IP.String()
885
+		networkSettings.Networks[n.Name()].GlobalIPv6PrefixLen = onesv6
886
+	}
887
+
888
+	return nil
889
+}
890
+
891
+// buildJoinOptions builds endpoint Join options from a given network.
892
+func buildJoinOptions(networkSettings *internalnetwork.Settings, n interface {
893
+	Name() string
894
+}) ([]libnetwork.EndpointOption, error) {
895
+	var joinOptions []libnetwork.EndpointOption
896
+	if epConfig, ok := networkSettings.Networks[n.Name()]; ok {
897
+		for _, str := range epConfig.Links {
898
+			name, alias, err := opts.ParseLink(str)
899
+			if err != nil {
900
+				return nil, err
901
+			}
902
+			joinOptions = append(joinOptions, libnetwork.CreateOptionAlias(name, alias))
903
+		}
904
+		for k, v := range epConfig.DriverOpts {
905
+			joinOptions = append(joinOptions, libnetwork.EndpointOptionGeneric(options.Generic{k: v}))
906
+		}
907
+	}
908
+
909
+	return joinOptions, nil
910
+}
... ...
@@ -156,7 +156,7 @@ func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
156 156
 				continue
157 157
 			}
158 158
 
159
-			ep, err := c.GetEndpointInNetwork(sn)
159
+			ep, err := getEndpointInNetwork(c.Name, sn)
160 160
 			if err != nil {
161 161
 				continue
162 162
 			}