github.com/jiasir/docker@v1.3.3-0.20170609024000-252e610103e7/daemon/network.go (about)

     1  package daemon
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"runtime"
     7  	"sort"
     8  	"strings"
     9  	"sync"
    10  
    11  	"github.com/Sirupsen/logrus"
    12  	apierrors "github.com/docker/docker/api/errors"
    13  	"github.com/docker/docker/api/types"
    14  	"github.com/docker/docker/api/types/network"
    15  	clustertypes "github.com/docker/docker/daemon/cluster/provider"
    16  	"github.com/docker/docker/pkg/plugingetter"
    17  	"github.com/docker/docker/runconfig"
    18  	"github.com/docker/libnetwork"
    19  	lncluster "github.com/docker/libnetwork/cluster"
    20  	"github.com/docker/libnetwork/driverapi"
    21  	"github.com/docker/libnetwork/ipamapi"
    22  	networktypes "github.com/docker/libnetwork/types"
    23  	"github.com/pkg/errors"
    24  	"golang.org/x/net/context"
    25  )
    26  
    27  // NetworkControllerEnabled checks if the networking stack is enabled.
    28  // This feature depends on OS primitives and it's disabled in systems like Windows.
    29  func (daemon *Daemon) NetworkControllerEnabled() bool {
    30  	return daemon.netController != nil
    31  }
    32  
    33  // FindNetwork function finds a network for a given string that can represent network name or id
    34  func (daemon *Daemon) FindNetwork(idName string) (libnetwork.Network, error) {
    35  	// Find by Name
    36  	n, err := daemon.GetNetworkByName(idName)
    37  	if err != nil && !isNoSuchNetworkError(err) {
    38  		return nil, err
    39  	}
    40  
    41  	if n != nil {
    42  		return n, nil
    43  	}
    44  
    45  	// Find by id
    46  	return daemon.GetNetworkByID(idName)
    47  }
    48  
    49  func isNoSuchNetworkError(err error) bool {
    50  	_, ok := err.(libnetwork.ErrNoSuchNetwork)
    51  	return ok
    52  }
    53  
    54  // GetNetworkByID function returns a network whose ID begins with the given prefix.
    55  // It fails with an error if no matching, or more than one matching, networks are found.
    56  func (daemon *Daemon) GetNetworkByID(partialID string) (libnetwork.Network, error) {
    57  	list := daemon.GetNetworksByID(partialID)
    58  
    59  	if len(list) == 0 {
    60  		return nil, libnetwork.ErrNoSuchNetwork(partialID)
    61  	}
    62  	if len(list) > 1 {
    63  		return nil, libnetwork.ErrInvalidID(partialID)
    64  	}
    65  	return list[0], nil
    66  }
    67  
    68  // GetNetworkByName function returns a network for a given network name.
    69  // If no network name is given, the default network is returned.
    70  func (daemon *Daemon) GetNetworkByName(name string) (libnetwork.Network, error) {
    71  	c := daemon.netController
    72  	if c == nil {
    73  		return nil, libnetwork.ErrNoSuchNetwork(name)
    74  	}
    75  	if name == "" {
    76  		name = c.Config().Daemon.DefaultNetwork
    77  	}
    78  	return c.NetworkByName(name)
    79  }
    80  
    81  // GetNetworksByID returns a list of networks whose ID partially matches zero or more networks
    82  func (daemon *Daemon) GetNetworksByID(partialID string) []libnetwork.Network {
    83  	c := daemon.netController
    84  	if c == nil {
    85  		return nil
    86  	}
    87  	list := []libnetwork.Network{}
    88  	l := func(nw libnetwork.Network) bool {
    89  		if strings.HasPrefix(nw.ID(), partialID) {
    90  			list = append(list, nw)
    91  		}
    92  		return false
    93  	}
    94  	c.WalkNetworks(l)
    95  
    96  	return list
    97  }
    98  
    99  // getAllNetworks returns a list containing all networks
   100  func (daemon *Daemon) getAllNetworks() []libnetwork.Network {
   101  	return daemon.netController.Networks()
   102  }
   103  
   104  type ingressJob struct {
   105  	create  *clustertypes.NetworkCreateRequest
   106  	ip      net.IP
   107  	jobDone chan struct{}
   108  }
   109  
   110  var (
   111  	ingressWorkerOnce  sync.Once
   112  	ingressJobsChannel chan *ingressJob
   113  	ingressID          string
   114  )
   115  
   116  func (daemon *Daemon) startIngressWorker() {
   117  	ingressJobsChannel = make(chan *ingressJob, 100)
   118  	go func() {
   119  		for {
   120  			select {
   121  			case r := <-ingressJobsChannel:
   122  				if r.create != nil {
   123  					daemon.setupIngress(r.create, r.ip, ingressID)
   124  					ingressID = r.create.ID
   125  				} else {
   126  					daemon.releaseIngress(ingressID)
   127  					ingressID = ""
   128  				}
   129  				close(r.jobDone)
   130  			}
   131  		}
   132  	}()
   133  }
   134  
   135  // enqueueIngressJob adds a ingress add/rm request to the worker queue.
   136  // It guarantees the worker is started.
   137  func (daemon *Daemon) enqueueIngressJob(job *ingressJob) {
   138  	ingressWorkerOnce.Do(daemon.startIngressWorker)
   139  	ingressJobsChannel <- job
   140  }
   141  
   142  // SetupIngress setups ingress networking.
   143  // The function returns a channel which will signal the caller when the programming is completed.
   144  func (daemon *Daemon) SetupIngress(create clustertypes.NetworkCreateRequest, nodeIP string) (<-chan struct{}, error) {
   145  	ip, _, err := net.ParseCIDR(nodeIP)
   146  	if err != nil {
   147  		return nil, err
   148  	}
   149  	done := make(chan struct{})
   150  	daemon.enqueueIngressJob(&ingressJob{&create, ip, done})
   151  	return done, nil
   152  }
   153  
   154  // ReleaseIngress releases the ingress networking.
   155  // The function returns a channel which will signal the caller when the programming is completed.
   156  func (daemon *Daemon) ReleaseIngress() (<-chan struct{}, error) {
   157  	done := make(chan struct{})
   158  	daemon.enqueueIngressJob(&ingressJob{nil, nil, done})
   159  	return done, nil
   160  }
   161  
   162  func (daemon *Daemon) setupIngress(create *clustertypes.NetworkCreateRequest, ip net.IP, staleID string) {
   163  	controller := daemon.netController
   164  	controller.AgentInitWait()
   165  
   166  	if staleID != "" && staleID != create.ID {
   167  		daemon.releaseIngress(staleID)
   168  	}
   169  
   170  	if _, err := daemon.createNetwork(create.NetworkCreateRequest, create.ID, true); err != nil {
   171  		// If it is any other error other than already
   172  		// exists error log error and return.
   173  		if _, ok := err.(libnetwork.NetworkNameError); !ok {
   174  			logrus.Errorf("Failed creating ingress network: %v", err)
   175  			return
   176  		}
   177  		// Otherwise continue down the call to create or recreate sandbox.
   178  	}
   179  
   180  	n, err := daemon.GetNetworkByID(create.ID)
   181  	if err != nil {
   182  		logrus.Errorf("Failed getting ingress network by id after creating: %v", err)
   183  	}
   184  
   185  	sb, err := controller.NewSandbox("ingress-sbox", libnetwork.OptionIngress())
   186  	if err != nil {
   187  		if _, ok := err.(networktypes.ForbiddenError); !ok {
   188  			logrus.Errorf("Failed creating ingress sandbox: %v", err)
   189  		}
   190  		return
   191  	}
   192  
   193  	ep, err := n.CreateEndpoint("ingress-endpoint", libnetwork.CreateOptionIpam(ip, nil, nil, nil))
   194  	if err != nil {
   195  		logrus.Errorf("Failed creating ingress endpoint: %v", err)
   196  		return
   197  	}
   198  
   199  	if err := ep.Join(sb, nil); err != nil {
   200  		logrus.Errorf("Failed joining ingress sandbox to ingress endpoint: %v", err)
   201  		return
   202  	}
   203  
   204  	if err := sb.EnableService(); err != nil {
   205  		logrus.Errorf("Failed enabling service for ingress sandbox")
   206  	}
   207  }
   208  
   209  func (daemon *Daemon) releaseIngress(id string) {
   210  	controller := daemon.netController
   211  	if err := controller.SandboxDestroy("ingress-sbox"); err != nil {
   212  		logrus.Errorf("Failed to delete ingress sandbox: %v", err)
   213  	}
   214  
   215  	if id == "" {
   216  		return
   217  	}
   218  
   219  	n, err := controller.NetworkByID(id)
   220  	if err != nil {
   221  		logrus.Errorf("failed to retrieve ingress network %s: %v", id, err)
   222  		return
   223  	}
   224  
   225  	for _, ep := range n.Endpoints() {
   226  		if err := ep.Delete(true); err != nil {
   227  			logrus.Errorf("Failed to delete endpoint %s (%s): %v", ep.Name(), ep.ID(), err)
   228  			return
   229  		}
   230  	}
   231  
   232  	if err := n.Delete(); err != nil {
   233  		logrus.Errorf("Failed to delete ingress network %s: %v", n.ID(), err)
   234  		return
   235  	}
   236  	return
   237  }
   238  
   239  // SetNetworkBootstrapKeys sets the bootstrap keys.
   240  func (daemon *Daemon) SetNetworkBootstrapKeys(keys []*networktypes.EncryptionKey) error {
   241  	err := daemon.netController.SetKeys(keys)
   242  	if err == nil {
   243  		// Upon successful key setting dispatch the keys available event
   244  		daemon.cluster.SendClusterEvent(lncluster.EventNetworkKeysAvailable)
   245  	}
   246  	return err
   247  }
   248  
   249  // UpdateAttachment notifies the attacher about the attachment config.
   250  func (daemon *Daemon) UpdateAttachment(networkName, networkID, containerID string, config *network.NetworkingConfig) error {
   251  	if daemon.clusterProvider == nil {
   252  		return fmt.Errorf("cluster provider is not initialized")
   253  	}
   254  
   255  	if err := daemon.clusterProvider.UpdateAttachment(networkName, containerID, config); err != nil {
   256  		return daemon.clusterProvider.UpdateAttachment(networkID, containerID, config)
   257  	}
   258  
   259  	return nil
   260  }
   261  
   262  // WaitForDetachment makes the cluster manager wait for detachment of
   263  // the container from the network.
   264  func (daemon *Daemon) WaitForDetachment(ctx context.Context, networkName, networkID, taskID, containerID string) error {
   265  	if daemon.clusterProvider == nil {
   266  		return fmt.Errorf("cluster provider is not initialized")
   267  	}
   268  
   269  	return daemon.clusterProvider.WaitForDetachment(ctx, networkName, networkID, taskID, containerID)
   270  }
   271  
   272  // CreateManagedNetwork creates an agent network.
   273  func (daemon *Daemon) CreateManagedNetwork(create clustertypes.NetworkCreateRequest) error {
   274  	_, err := daemon.createNetwork(create.NetworkCreateRequest, create.ID, true)
   275  	return err
   276  }
   277  
   278  // CreateNetwork creates a network with the given name, driver and other optional parameters
   279  func (daemon *Daemon) CreateNetwork(create types.NetworkCreateRequest) (*types.NetworkCreateResponse, error) {
   280  	resp, err := daemon.createNetwork(create, "", false)
   281  	if err != nil {
   282  		return nil, err
   283  	}
   284  	return resp, err
   285  }
   286  
   287  func (daemon *Daemon) createNetwork(create types.NetworkCreateRequest, id string, agent bool) (*types.NetworkCreateResponse, error) {
   288  	if runconfig.IsPreDefinedNetwork(create.Name) && !agent {
   289  		err := fmt.Errorf("%s is a pre-defined network and cannot be created", create.Name)
   290  		return nil, apierrors.NewRequestForbiddenError(err)
   291  	}
   292  
   293  	var warning string
   294  	nw, err := daemon.GetNetworkByName(create.Name)
   295  	if err != nil {
   296  		if _, ok := err.(libnetwork.ErrNoSuchNetwork); !ok {
   297  			return nil, err
   298  		}
   299  	}
   300  	if nw != nil {
   301  		// check if user defined CheckDuplicate, if set true, return err
   302  		// otherwise prepare a warning message
   303  		if create.CheckDuplicate {
   304  			return nil, libnetwork.NetworkNameError(create.Name)
   305  		}
   306  		warning = fmt.Sprintf("Network with name %s (id : %s) already exists", nw.Name(), nw.ID())
   307  	}
   308  
   309  	c := daemon.netController
   310  	driver := create.Driver
   311  	if driver == "" {
   312  		driver = c.Config().Daemon.DefaultDriver
   313  	}
   314  
   315  	nwOptions := []libnetwork.NetworkOption{
   316  		libnetwork.NetworkOptionEnableIPv6(create.EnableIPv6),
   317  		libnetwork.NetworkOptionDriverOpts(create.Options),
   318  		libnetwork.NetworkOptionLabels(create.Labels),
   319  		libnetwork.NetworkOptionAttachable(create.Attachable),
   320  		libnetwork.NetworkOptionIngress(create.Ingress),
   321  		libnetwork.NetworkOptionScope(create.Scope),
   322  	}
   323  
   324  	if create.ConfigOnly {
   325  		nwOptions = append(nwOptions, libnetwork.NetworkOptionConfigOnly())
   326  	}
   327  
   328  	if create.IPAM != nil {
   329  		ipam := create.IPAM
   330  		v4Conf, v6Conf, err := getIpamConfig(ipam.Config)
   331  		if err != nil {
   332  			return nil, err
   333  		}
   334  		nwOptions = append(nwOptions, libnetwork.NetworkOptionIpam(ipam.Driver, "", v4Conf, v6Conf, ipam.Options))
   335  	}
   336  
   337  	if create.Internal {
   338  		nwOptions = append(nwOptions, libnetwork.NetworkOptionInternalNetwork())
   339  	}
   340  	if agent {
   341  		nwOptions = append(nwOptions, libnetwork.NetworkOptionDynamic())
   342  		nwOptions = append(nwOptions, libnetwork.NetworkOptionPersist(false))
   343  	}
   344  
   345  	if create.ConfigFrom != nil {
   346  		nwOptions = append(nwOptions, libnetwork.NetworkOptionConfigFrom(create.ConfigFrom.Network))
   347  	}
   348  
   349  	n, err := c.NewNetwork(driver, create.Name, id, nwOptions...)
   350  	if err != nil {
   351  		if _, ok := err.(libnetwork.ErrDataStoreNotInitialized); ok {
   352  			return nil, errors.New("This node is not a swarm manager. Use \"docker swarm init\" or \"docker swarm join\" to connect this node to swarm and try again.")
   353  		}
   354  		return nil, err
   355  	}
   356  
   357  	daemon.pluginRefCount(driver, driverapi.NetworkPluginEndpointType, plugingetter.Acquire)
   358  	if create.IPAM != nil {
   359  		daemon.pluginRefCount(create.IPAM.Driver, ipamapi.PluginEndpointType, plugingetter.Acquire)
   360  	}
   361  	daemon.LogNetworkEvent(n, "create")
   362  
   363  	return &types.NetworkCreateResponse{
   364  		ID:      n.ID(),
   365  		Warning: warning,
   366  	}, nil
   367  }
   368  
   369  func (daemon *Daemon) pluginRefCount(driver, capability string, mode int) {
   370  	var builtinDrivers []string
   371  
   372  	if capability == driverapi.NetworkPluginEndpointType {
   373  		builtinDrivers = daemon.netController.BuiltinDrivers()
   374  	} else if capability == ipamapi.PluginEndpointType {
   375  		builtinDrivers = daemon.netController.BuiltinIPAMDrivers()
   376  	}
   377  
   378  	for _, d := range builtinDrivers {
   379  		if d == driver {
   380  			return
   381  		}
   382  	}
   383  
   384  	if daemon.PluginStore != nil {
   385  		_, err := daemon.PluginStore.Get(driver, capability, mode)
   386  		if err != nil {
   387  			logrus.WithError(err).WithFields(logrus.Fields{"mode": mode, "driver": driver}).Error("Error handling plugin refcount operation")
   388  		}
   389  	}
   390  }
   391  
   392  func getIpamConfig(data []network.IPAMConfig) ([]*libnetwork.IpamConf, []*libnetwork.IpamConf, error) {
   393  	ipamV4Cfg := []*libnetwork.IpamConf{}
   394  	ipamV6Cfg := []*libnetwork.IpamConf{}
   395  	for _, d := range data {
   396  		iCfg := libnetwork.IpamConf{}
   397  		iCfg.PreferredPool = d.Subnet
   398  		iCfg.SubPool = d.IPRange
   399  		iCfg.Gateway = d.Gateway
   400  		iCfg.AuxAddresses = d.AuxAddress
   401  		ip, _, err := net.ParseCIDR(d.Subnet)
   402  		if err != nil {
   403  			return nil, nil, fmt.Errorf("Invalid subnet %s : %v", d.Subnet, err)
   404  		}
   405  		if ip.To4() != nil {
   406  			ipamV4Cfg = append(ipamV4Cfg, &iCfg)
   407  		} else {
   408  			ipamV6Cfg = append(ipamV6Cfg, &iCfg)
   409  		}
   410  	}
   411  	return ipamV4Cfg, ipamV6Cfg, nil
   412  }
   413  
   414  // UpdateContainerServiceConfig updates a service configuration.
   415  func (daemon *Daemon) UpdateContainerServiceConfig(containerName string, serviceConfig *clustertypes.ServiceConfig) error {
   416  	container, err := daemon.GetContainer(containerName)
   417  	if err != nil {
   418  		return err
   419  	}
   420  
   421  	container.NetworkSettings.Service = serviceConfig
   422  	return nil
   423  }
   424  
   425  // ConnectContainerToNetwork connects the given container to the given
   426  // network. If either cannot be found, an err is returned. If the
   427  // network cannot be set up, an err is returned.
   428  func (daemon *Daemon) ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error {
   429  	if runtime.GOOS == "solaris" {
   430  		return errors.New("docker network connect is unsupported on Solaris platform")
   431  	}
   432  	container, err := daemon.GetContainer(containerName)
   433  	if err != nil {
   434  		return err
   435  	}
   436  	return daemon.ConnectToNetwork(container, networkName, endpointConfig)
   437  }
   438  
   439  // DisconnectContainerFromNetwork disconnects the given container from
   440  // the given network. If either cannot be found, an err is returned.
   441  func (daemon *Daemon) DisconnectContainerFromNetwork(containerName string, networkName string, force bool) error {
   442  	if runtime.GOOS == "solaris" {
   443  		return errors.New("docker network disconnect is unsupported on Solaris platform")
   444  	}
   445  	container, err := daemon.GetContainer(containerName)
   446  	if err != nil {
   447  		if force {
   448  			return daemon.ForceEndpointDelete(containerName, networkName)
   449  		}
   450  		return err
   451  	}
   452  	return daemon.DisconnectFromNetwork(container, networkName, force)
   453  }
   454  
   455  // GetNetworkDriverList returns the list of plugins drivers
   456  // registered for network.
   457  func (daemon *Daemon) GetNetworkDriverList() []string {
   458  	if !daemon.NetworkControllerEnabled() {
   459  		return nil
   460  	}
   461  
   462  	pluginList := daemon.netController.BuiltinDrivers()
   463  
   464  	managedPlugins := daemon.PluginStore.GetAllManagedPluginsByCap(driverapi.NetworkPluginEndpointType)
   465  
   466  	for _, plugin := range managedPlugins {
   467  		pluginList = append(pluginList, plugin.Name())
   468  	}
   469  
   470  	pluginMap := make(map[string]bool)
   471  	for _, plugin := range pluginList {
   472  		pluginMap[plugin] = true
   473  	}
   474  
   475  	networks := daemon.netController.Networks()
   476  
   477  	for _, network := range networks {
   478  		if !pluginMap[network.Type()] {
   479  			pluginList = append(pluginList, network.Type())
   480  			pluginMap[network.Type()] = true
   481  		}
   482  	}
   483  
   484  	sort.Strings(pluginList)
   485  
   486  	return pluginList
   487  }
   488  
   489  // DeleteManagedNetwork deletes an agent network.
   490  func (daemon *Daemon) DeleteManagedNetwork(networkID string) error {
   491  	return daemon.deleteNetwork(networkID, true)
   492  }
   493  
   494  // DeleteNetwork destroys a network unless it's one of docker's predefined networks.
   495  func (daemon *Daemon) DeleteNetwork(networkID string) error {
   496  	return daemon.deleteNetwork(networkID, false)
   497  }
   498  
   499  func (daemon *Daemon) deleteNetwork(networkID string, dynamic bool) error {
   500  	nw, err := daemon.FindNetwork(networkID)
   501  	if err != nil {
   502  		return err
   503  	}
   504  
   505  	if runconfig.IsPreDefinedNetwork(nw.Name()) && !dynamic {
   506  		err := fmt.Errorf("%s is a pre-defined network and cannot be removed", nw.Name())
   507  		return apierrors.NewRequestForbiddenError(err)
   508  	}
   509  
   510  	if dynamic && !nw.Info().Dynamic() {
   511  		if runconfig.IsPreDefinedNetwork(nw.Name()) {
   512  			// Predefined networks now support swarm services. Make this
   513  			// a no-op when cluster requests to remove the predefined network.
   514  			return nil
   515  		}
   516  		err := fmt.Errorf("%s is not a dynamic network", nw.Name())
   517  		return apierrors.NewRequestForbiddenError(err)
   518  	}
   519  
   520  	if err := nw.Delete(); err != nil {
   521  		return err
   522  	}
   523  
   524  	// If this is not a configuration only network, we need to
   525  	// update the corresponding remote drivers' reference counts
   526  	if !nw.Info().ConfigOnly() {
   527  		daemon.pluginRefCount(nw.Type(), driverapi.NetworkPluginEndpointType, plugingetter.Release)
   528  		ipamType, _, _, _ := nw.Info().IpamConfig()
   529  		daemon.pluginRefCount(ipamType, ipamapi.PluginEndpointType, plugingetter.Release)
   530  		daemon.LogNetworkEvent(nw, "destroy")
   531  	}
   532  
   533  	return nil
   534  }
   535  
   536  // GetNetworks returns a list of all networks
   537  func (daemon *Daemon) GetNetworks() []libnetwork.Network {
   538  	return daemon.getAllNetworks()
   539  }
   540  
   541  // clearAttachableNetworks removes the attachable networks
   542  // after disconnecting any connected container
   543  func (daemon *Daemon) clearAttachableNetworks() {
   544  	for _, n := range daemon.GetNetworks() {
   545  		if !n.Info().Attachable() {
   546  			continue
   547  		}
   548  		for _, ep := range n.Endpoints() {
   549  			epInfo := ep.Info()
   550  			if epInfo == nil {
   551  				continue
   552  			}
   553  			sb := epInfo.Sandbox()
   554  			if sb == nil {
   555  				continue
   556  			}
   557  			containerID := sb.ContainerID()
   558  			if err := daemon.DisconnectContainerFromNetwork(containerID, n.ID(), true); err != nil {
   559  				logrus.Warnf("Failed to disconnect container %s from swarm network %s on cluster leave: %v",
   560  					containerID, n.Name(), err)
   561  			}
   562  		}
   563  		if err := daemon.DeleteManagedNetwork(n.ID()); err != nil {
   564  			logrus.Warnf("Failed to remove swarm network %s on cluster leave: %v", n.Name(), err)
   565  		}
   566  	}
   567  }