// User specified ip address is acceptable only for networks with user specified subnets. func validateNetworkingConfig(n libnetwork.Network, epConfig *networktypes.EndpointSettings) error { if !hasUserDefinedIPAddress(epConfig) { return nil } _, nwIPv4Configs, nwIPv6Configs := n.Info().IpamConfig() for _, s := range []struct { ipConfigured bool subnetConfigs []*libnetwork.IpamConf }{ { ipConfigured: len(epConfig.IPAMConfig.IPv4Address) > 0, subnetConfigs: nwIPv4Configs, }, { ipConfigured: len(epConfig.IPAMConfig.IPv6Address) > 0, subnetConfigs: nwIPv6Configs, }, } { if s.ipConfigured { foundSubnet := false for _, cfg := range s.subnetConfigs { if len(cfg.PreferredPool) > 0 { foundSubnet = true break } } if !foundSubnet { return runconfig.ErrUnsupportedNetworkNoSubnetAndIP } } } return nil }
func buildNetworkResource(nw libnetwork.Network) *types.NetworkResource { r := &types.NetworkResource{} if nw == nil { return r } info := nw.Info() r.Name = nw.Name() r.ID = nw.ID() r.Scope = info.Scope() r.Driver = nw.Type() r.EnableIPv6 = info.IPv6Enabled() r.Internal = info.Internal() r.Options = info.DriverOptions() r.Containers = make(map[string]types.EndpointResource) buildIpamResources(r, info) r.Internal = info.Internal() r.Labels = info.Labels() epl := nw.Endpoints() for _, e := range epl { ei := e.Info() if ei == nil { continue } sb := ei.Sandbox() key := "ep-" + e.ID() if sb != nil { key = sb.ContainerID() } r.Containers[key] = buildEndpointResource(e) } return r }
func buildNetworkResource(nw libnetwork.Network) *types.NetworkResource { r := &types.NetworkResource{} if nw == nil { return r } r.Name = nw.Name() r.ID = nw.ID() r.Scope = nw.Info().Scope() r.Driver = nw.Type() r.EnableIPv6 = nw.Info().IPv6Enabled() r.Internal = nw.Info().Internal() r.Options = nw.Info().DriverOptions() r.Containers = make(map[string]types.EndpointResource) buildIpamResources(r, nw) r.Internal = nw.Info().Internal() epl := nw.Endpoints() for _, e := range epl { ei := e.Info() if ei == nil { continue } sb := ei.Sandbox() if sb == nil { continue } r.Containers[sb.ContainerID()] = buildEndpointResource(e) } return r }
func buildNetworkResource(nw libnetwork.Network) *types.NetworkResource { r := &types.NetworkResource{} if nw == nil { return r } r.Name = nw.Name() r.ID = nw.ID() r.Scope = nw.Info().Scope() r.Driver = nw.Type() r.Containers = make(map[string]types.EndpointResource) r.Labels = nw.Info().Labels() buildIpamResources(r, nw) epl := nw.Endpoints() for _, e := range epl { sb := e.Info().Sandbox() if sb == nil { continue } r.Containers[sb.ContainerID()] = buildEndpointResource(e) } return r }
func (daemon *Daemon) disconnectFromNetwork(container *container.Container, n libnetwork.Network, force bool) error { var ( ep libnetwork.Endpoint sbox libnetwork.Sandbox ) s := func(current libnetwork.Endpoint) bool { epInfo := current.Info() if epInfo == nil { return false } if sb := epInfo.Sandbox(); sb != nil { if sb.ContainerID() == container.ID { ep = current sbox = sb return true } } return false } n.WalkEndpoints(s) if ep == nil && force { epName := strings.TrimPrefix(container.Name, "/") ep, err := n.EndpointByName(epName) if err != nil { return err } return ep.Delete(force) } if ep == nil { return fmt.Errorf("container %s is not connected to the network", container.ID) } if err := ep.Leave(sbox); err != nil { return fmt.Errorf("container %s failed to leave network %s: %v", container.ID, n.Name(), err) } container.NetworkSettings.Ports = getPortMapInfo(sbox) if err := ep.Delete(false); err != nil { return fmt.Errorf("endpoint delete failed for container %s on network %s: %v", container.ID, n.Name(), err) } delete(container.NetworkSettings.Networks, n.Name()) if daemon.clusterProvider != nil && n.Info().Dynamic() && !container.Managed { if err := daemon.clusterProvider.DetachNetwork(n.Name(), container.ID); err != nil { logrus.Warnf("error detaching from network %s: %v", n.Name(), err) if err := daemon.clusterProvider.DetachNetwork(n.ID(), container.ID); err != nil { logrus.Warnf("error detaching from network %s: %v", n.ID(), err) } } } return nil }
func buildIpamResources(r *types.NetworkResource, nw libnetwork.Network) { id, opts, ipv4conf, ipv6conf := nw.Info().IpamConfig() ipv4Info, ipv6Info := nw.Info().IpamInfo() r.IPAM.Driver = id r.IPAM.Options = opts r.IPAM.Config = []network.IPAMConfig{} for _, ip4 := range ipv4conf { if ip4.PreferredPool == "" { continue } iData := network.IPAMConfig{} iData.Subnet = ip4.PreferredPool iData.IPRange = ip4.SubPool iData.Gateway = ip4.Gateway iData.AuxAddress = ip4.AuxAddresses r.IPAM.Config = append(r.IPAM.Config, iData) } if len(r.IPAM.Config) == 0 { for _, ip4Info := range ipv4Info { iData := network.IPAMConfig{} iData.Subnet = ip4Info.IPAMData.Pool.String() iData.Gateway = ip4Info.IPAMData.Gateway.String() r.IPAM.Config = append(r.IPAM.Config, iData) } } hasIpv6Conf := false for _, ip6 := range ipv6conf { if ip6.PreferredPool == "" { continue } hasIpv6Conf = true iData := network.IPAMConfig{} iData.Subnet = ip6.PreferredPool iData.IPRange = ip6.SubPool iData.Gateway = ip6.Gateway iData.AuxAddress = ip6.AuxAddresses r.IPAM.Config = append(r.IPAM.Config, iData) } if !hasIpv6Conf { for _, ip6Info := range ipv6Info { iData := network.IPAMConfig{} iData.Subnet = ip6Info.IPAMData.Pool.String() iData.Gateway = ip6Info.IPAMData.Gateway.String() r.IPAM.Config = append(r.IPAM.Config, iData) } } }
// updateContainerNetworkSettings update the network settings func (daemon *Daemon) updateContainerNetworkSettings(container *container.Container, endpointsConfig map[string]*networktypes.EndpointSettings) error { var ( n libnetwork.Network err error ) mode := container.HostConfig.NetworkMode if container.Config.NetworkDisabled || mode.IsContainer() { return nil } networkName := mode.NetworkName() if mode.IsDefault() { networkName = daemon.netController.Config().Daemon.DefaultNetwork } if mode.IsUserDefined() { n, err = daemon.FindNetwork(networkName) if err != nil { return err } if !container.Managed && n.Info().Dynamic() { return errClusterNetworkOnRun(networkName) } networkName = n.Name() } if container.NetworkSettings == nil { container.NetworkSettings = &network.Settings{} } if len(endpointsConfig) > 0 { container.NetworkSettings.Networks = endpointsConfig } if container.NetworkSettings.Networks == nil { container.NetworkSettings.Networks = make(map[string]*networktypes.EndpointSettings) container.NetworkSettings.Networks[networkName] = new(networktypes.EndpointSettings) } if !mode.IsUserDefined() { return nil } // Make sure to internally store the per network endpoint config by network name if _, ok := container.NetworkSettings.Networks[networkName]; ok { return nil } if nwConfig, ok := container.NetworkSettings.Networks[n.ID()]; ok { container.NetworkSettings.Networks[networkName] = nwConfig delete(container.NetworkSettings.Networks, n.ID()) return nil } return nil }
func (n *networkRouter) buildNetworkResource(nw libnetwork.Network) *types.NetworkResource { r := &types.NetworkResource{} if nw == nil { return r } info := nw.Info() r.Name = nw.Name() r.ID = nw.ID() r.Created = info.Created() r.Scope = info.Scope() if n.clusterProvider.IsManager() { if _, err := n.clusterProvider.GetNetwork(nw.Name()); err == nil { r.Scope = "swarm" } } else if info.Dynamic() { r.Scope = "swarm" } r.Driver = nw.Type() r.EnableIPv6 = info.IPv6Enabled() r.Internal = info.Internal() r.Attachable = info.Attachable() r.Options = info.DriverOptions() r.Containers = make(map[string]types.EndpointResource) buildIpamResources(r, info) r.Labels = info.Labels() peers := info.Peers() if len(peers) != 0 { r.Peers = buildPeerInfoResources(peers) } epl := nw.Endpoints() for _, e := range epl { ei := e.Info() if ei == nil { continue } sb := ei.Sandbox() tmpID := e.ID() key := "ep-" + tmpID if sb != nil { key = sb.ContainerID() } r.Containers[key] = buildEndpointResource(tmpID, e.Name(), ei) } return r }
func buildIpamResources(r *types.NetworkResource, nw libnetwork.Network) { id, ipv4conf, ipv6conf := nw.Info().IpamConfig() r.IPAM.Driver = id r.IPAM.Config = []network.IPAMConfig{} for _, ip4 := range ipv4conf { iData := network.IPAMConfig{} iData.Subnet = ip4.PreferredPool iData.IPRange = ip4.SubPool iData.Gateway = ip4.Gateway iData.AuxAddress = ip4.AuxAddresses r.IPAM.Config = append(r.IPAM.Config, iData) } for _, ip6 := range ipv6conf { iData := network.IPAMConfig{} iData.Subnet = ip6.PreferredPool iData.IPRange = ip6.SubPool iData.Gateway = ip6.Gateway iData.AuxAddress = ip6.AuxAddresses r.IPAM.Config = append(r.IPAM.Config, iData) } }
// BuildCreateEndpointOptions builds endpoint options from a given network. func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network, epConfig *networktypes.EndpointSettings, sb libnetwork.Sandbox, daemonDNS []string) ([]libnetwork.EndpointOption, error) { var ( bindings = make(nat.PortMap) pbList []types.PortBinding exposeList []types.TransportPort createOptions []libnetwork.EndpointOption ) defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName() if (!container.EnableServiceDiscoveryOnDefaultNetwork() && n.Name() == defaultNetName) || container.NetworkSettings.IsAnonymousEndpoint { createOptions = append(createOptions, libnetwork.CreateOptionAnonymous()) } if epConfig != nil { ipam := epConfig.IPAMConfig if ipam != nil && (ipam.IPv4Address != "" || ipam.IPv6Address != "" || len(ipam.LinkLocalIPs) > 0) { var ipList []net.IP for _, ips := range ipam.LinkLocalIPs { if ip := net.ParseIP(ips); ip != nil { ipList = append(ipList, ip) } } createOptions = append(createOptions, libnetwork.CreateOptionIpam(net.ParseIP(ipam.IPv4Address), net.ParseIP(ipam.IPv6Address), ipList, nil)) } for _, alias := range epConfig.Aliases { createOptions = append(createOptions, libnetwork.CreateOptionMyAlias(alias)) } } if container.NetworkSettings.Service != nil { svcCfg := container.NetworkSettings.Service var vip string if svcCfg.VirtualAddresses[n.ID()] != nil { vip = svcCfg.VirtualAddresses[n.ID()].IPv4 } var portConfigs []*libnetwork.PortConfig for _, portConfig := range svcCfg.ExposedPorts { portConfigs = append(portConfigs, &libnetwork.PortConfig{ Name: portConfig.Name, Protocol: libnetwork.PortConfig_Protocol(portConfig.Protocol), TargetPort: portConfig.TargetPort, PublishedPort: portConfig.PublishedPort, }) } createOptions = append(createOptions, libnetwork.CreateOptionService(svcCfg.Name, svcCfg.ID, net.ParseIP(vip), portConfigs, svcCfg.Aliases[n.ID()])) } if !containertypes.NetworkMode(n.Name()).IsUserDefined() { createOptions = append(createOptions, libnetwork.CreateOptionDisableResolution()) } // configs that are applicable only for the endpoint in the network // to which container was connected to on docker run. // Ideally all these network-specific endpoint configurations must be moved under // container.NetworkSettings.Networks[n.Name()] if n.Name() == container.HostConfig.NetworkMode.NetworkName() || (n.Name() == defaultNetName && container.HostConfig.NetworkMode.IsDefault()) { if container.Config.MacAddress != "" { mac, err := net.ParseMAC(container.Config.MacAddress) if err != nil { return nil, err } genericOption := options.Generic{ netlabel.MacAddress: mac, } createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption)) } } // Port-mapping rules belong to the container & applicable only to non-internal networks portmaps := GetSandboxPortMapInfo(sb) if n.Info().Internal() || len(portmaps) > 0 { return createOptions, nil } if container.HostConfig.PortBindings != nil { for p, b := range container.HostConfig.PortBindings { bindings[p] = []nat.PortBinding{} for _, bb := range b { bindings[p] = append(bindings[p], nat.PortBinding{ HostIP: bb.HostIP, HostPort: bb.HostPort, }) } } } portSpecs := container.Config.ExposedPorts ports := make([]nat.Port, len(portSpecs)) var i int for p := range portSpecs { ports[i] = p i++ } nat.SortPortMap(ports, bindings) for _, port := range ports { expose := types.TransportPort{} expose.Proto = types.ParseProtocol(port.Proto()) expose.Port = uint16(port.Int()) exposeList = append(exposeList, expose) pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto} binding := bindings[port] for i := 0; i < len(binding); i++ { pbCopy := pb.GetCopy() newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort)) var portStart, portEnd int if err == nil { portStart, portEnd, err = newP.Range() } if err != nil { return nil, fmt.Errorf("Error parsing HostPort value(%s):%v", binding[i].HostPort, err) } pbCopy.HostPort = uint16(portStart) pbCopy.HostPortEnd = uint16(portEnd) pbCopy.HostIP = net.ParseIP(binding[i].HostIP) pbList = append(pbList, pbCopy) } if container.HostConfig.PublishAllPorts && len(binding) == 0 { pbList = append(pbList, pb) } } var dns []string if len(container.HostConfig.DNS) > 0 { dns = container.HostConfig.DNS } else if len(daemonDNS) > 0 { dns = daemonDNS } if len(dns) > 0 { createOptions = append(createOptions, libnetwork.CreateOptionDNS(dns)) } createOptions = append(createOptions, libnetwork.CreateOptionPortMapping(pbList), libnetwork.CreateOptionExposedPorts(exposeList)) return createOptions, nil }
// BuildCreateEndpointOptions builds endpoint options from a given network. func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network, epConfig *network.EndpointSettings, sb libnetwork.Sandbox) ([]libnetwork.EndpointOption, error) { var ( portSpecs = make(nat.PortSet) bindings = make(nat.PortMap) pbList []types.PortBinding exposeList []types.TransportPort createOptions []libnetwork.EndpointOption ) if n.Name() == "bridge" || container.NetworkSettings.IsAnonymousEndpoint { createOptions = append(createOptions, libnetwork.CreateOptionAnonymous()) } if epConfig != nil { ipam := epConfig.IPAMConfig if ipam != nil && (ipam.IPv4Address != "" || ipam.IPv6Address != "") { createOptions = append(createOptions, libnetwork.CreateOptionIpam(net.ParseIP(ipam.IPv4Address), net.ParseIP(ipam.IPv6Address), nil)) } for _, alias := range epConfig.Aliases { createOptions = append(createOptions, libnetwork.CreateOptionMyAlias(alias)) } } if !containertypes.NetworkMode(n.Name()).IsUserDefined() { createOptions = append(createOptions, libnetwork.CreateOptionDisableResolution()) } // configs that are applicable only for the endpoint in the network // to which container was connected to on docker run. // Ideally all these network-specific endpoint configurations must be moved under // container.NetworkSettings.Networks[n.Name()] if n.Name() == container.HostConfig.NetworkMode.NetworkName() || (n.Name() == "bridge" && container.HostConfig.NetworkMode.IsDefault()) { if container.Config.MacAddress != "" { mac, err := net.ParseMAC(container.Config.MacAddress) if err != nil { return nil, err } genericOption := options.Generic{ netlabel.MacAddress: mac, } createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption)) } } // Port-mapping rules belong to the container & applicable only to non-internal networks portmaps := getSandboxPortMapInfo(sb) if n.Info().Internal() || len(portmaps) > 0 { return createOptions, nil } if container.Config.ExposedPorts != nil { portSpecs = container.Config.ExposedPorts } if container.HostConfig.PortBindings != nil { for p, b := range container.HostConfig.PortBindings { bindings[p] = []nat.PortBinding{} for _, bb := range b { bindings[p] = append(bindings[p], nat.PortBinding{ HostIP: bb.HostIP, HostPort: bb.HostPort, }) } } } ports := make([]nat.Port, len(portSpecs)) var i int for p := range portSpecs { ports[i] = p i++ } nat.SortPortMap(ports, bindings) for _, port := range ports { expose := types.TransportPort{} expose.Proto = types.ParseProtocol(port.Proto()) expose.Port = uint16(port.Int()) exposeList = append(exposeList, expose) pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto} binding := bindings[port] for i := 0; i < len(binding); i++ { pbCopy := pb.GetCopy() newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort)) var portStart, portEnd int if err == nil { portStart, portEnd, err = newP.Range() } if err != nil { return nil, derr.ErrorCodeHostPort.WithArgs(binding[i].HostPort, err) } pbCopy.HostPort = uint16(portStart) pbCopy.HostPortEnd = uint16(portEnd) pbCopy.HostIP = net.ParseIP(binding[i].HostIP) pbList = append(pbList, pbCopy) } if container.HostConfig.PublishAllPorts && len(binding) == 0 { pbList = append(pbList, pb) } } createOptions = append(createOptions, libnetwork.CreateOptionPortMapping(pbList), libnetwork.CreateOptionExposedPorts(exposeList)) return createOptions, nil }
func (daemon *Daemon) initNetworkController(config *Config, activeSandboxes map[string]interface{}) (libnetwork.NetworkController, error) { netOptions, err := daemon.networkOptions(config, nil, nil) if err != nil { return nil, err } controller, err := libnetwork.New(netOptions...) if err != nil { return nil, fmt.Errorf("error obtaining controller instance: %v", err) } hnsresponse, err := hcsshim.HNSListNetworkRequest("GET", "", "") if err != nil { return nil, err } // Remove networks not present in HNS for _, v := range controller.Networks() { options := v.Info().DriverOptions() hnsid := options[winlibnetwork.HNSID] found := false for _, v := range hnsresponse { if v.Id == hnsid { found = true break } } if !found { // global networks should not be deleted by local HNS if v.Info().Scope() != datastore.GlobalScope { err = v.Delete() if err != nil { logrus.Errorf("Error occurred when removing network %v", err) } } } } _, err = controller.NewNetwork("null", "none", "", libnetwork.NetworkOptionPersist(false)) if err != nil { return nil, err } defaultNetworkExists := false if network, err := controller.NetworkByName(runconfig.DefaultDaemonNetworkMode().NetworkName()); err == nil { options := network.Info().DriverOptions() for _, v := range hnsresponse { if options[winlibnetwork.HNSID] == v.Id { defaultNetworkExists = true break } } } // discover and add HNS networks to windows // network that exist are removed and added again for _, v := range hnsresponse { var n libnetwork.Network s := func(current libnetwork.Network) bool { options := current.Info().DriverOptions() if options[winlibnetwork.HNSID] == v.Id { n = current return true } return false } controller.WalkNetworks(s) if n != nil { // global networks should not be deleted by local HNS if n.Info().Scope() == datastore.GlobalScope { continue } v.Name = n.Name() // This will not cause network delete from HNS as the network // is not yet populated in the libnetwork windows driver n.Delete() } netOption := map[string]string{ winlibnetwork.NetworkName: v.Name, winlibnetwork.HNSID: v.Id, } v4Conf := []*libnetwork.IpamConf{} for _, subnet := range v.Subnets { ipamV4Conf := libnetwork.IpamConf{} ipamV4Conf.PreferredPool = subnet.AddressPrefix ipamV4Conf.Gateway = subnet.GatewayAddress v4Conf = append(v4Conf, &ipamV4Conf) } name := v.Name // If there is no nat network create one from the first NAT network // encountered if !defaultNetworkExists && runconfig.DefaultDaemonNetworkMode() == containertypes.NetworkMode(strings.ToLower(v.Type)) { name = runconfig.DefaultDaemonNetworkMode().NetworkName() defaultNetworkExists = true } v6Conf := []*libnetwork.IpamConf{} _, err := controller.NewNetwork(strings.ToLower(v.Type), name, "", libnetwork.NetworkOptionGeneric(options.Generic{ netlabel.GenericData: netOption, }), libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil), ) if err != nil { logrus.Errorf("Error occurred when creating network %v", err) } } if !config.DisableBridge { // Initialize default driver "bridge" if err := initBridgeDriver(controller, config); err != nil { return nil, err } } return controller, nil }