github.com/gdevillele/moby@v1.13.0/daemon/network.go (about)

     1  package daemon
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"runtime"
     7  	"sort"
     8  	"strings"
     9  
    10  	"github.com/Sirupsen/logrus"
    11  	apierrors "github.com/docker/docker/api/errors"
    12  	"github.com/docker/docker/api/types"
    13  	"github.com/docker/docker/api/types/network"
    14  	clustertypes "github.com/docker/docker/daemon/cluster/provider"
    15  	"github.com/docker/docker/pkg/plugingetter"
    16  	"github.com/docker/docker/runconfig"
    17  	"github.com/docker/libnetwork"
    18  	"github.com/docker/libnetwork/driverapi"
    19  	"github.com/docker/libnetwork/ipamapi"
    20  	networktypes "github.com/docker/libnetwork/types"
    21  	"github.com/pkg/errors"
    22  	"golang.org/x/net/context"
    23  )
    24  
    25  // NetworkControllerEnabled checks if the networking stack is enabled.
    26  // This feature depends on OS primitives and it's disabled in systems like Windows.
    27  func (daemon *Daemon) NetworkControllerEnabled() bool {
    28  	return daemon.netController != nil
    29  }
    30  
    31  // FindNetwork function finds a network for a given string that can represent network name or id
    32  func (daemon *Daemon) FindNetwork(idName string) (libnetwork.Network, error) {
    33  	// Find by Name
    34  	n, err := daemon.GetNetworkByName(idName)
    35  	if err != nil && !isNoSuchNetworkError(err) {
    36  		return nil, err
    37  	}
    38  
    39  	if n != nil {
    40  		return n, nil
    41  	}
    42  
    43  	// Find by id
    44  	return daemon.GetNetworkByID(idName)
    45  }
    46  
    47  func isNoSuchNetworkError(err error) bool {
    48  	_, ok := err.(libnetwork.ErrNoSuchNetwork)
    49  	return ok
    50  }
    51  
    52  // GetNetworkByID function returns a network whose ID begins with the given prefix.
    53  // It fails with an error if no matching, or more than one matching, networks are found.
    54  func (daemon *Daemon) GetNetworkByID(partialID string) (libnetwork.Network, error) {
    55  	list := daemon.GetNetworksByID(partialID)
    56  
    57  	if len(list) == 0 {
    58  		return nil, libnetwork.ErrNoSuchNetwork(partialID)
    59  	}
    60  	if len(list) > 1 {
    61  		return nil, libnetwork.ErrInvalidID(partialID)
    62  	}
    63  	return list[0], nil
    64  }
    65  
    66  // GetNetworkByName function returns a network for a given network name.
    67  // If no network name is given, the default network is returned.
    68  func (daemon *Daemon) GetNetworkByName(name string) (libnetwork.Network, error) {
    69  	c := daemon.netController
    70  	if c == nil {
    71  		return nil, libnetwork.ErrNoSuchNetwork(name)
    72  	}
    73  	if name == "" {
    74  		name = c.Config().Daemon.DefaultNetwork
    75  	}
    76  	return c.NetworkByName(name)
    77  }
    78  
    79  // GetNetworksByID returns a list of networks whose ID partially matches zero or more networks
    80  func (daemon *Daemon) GetNetworksByID(partialID string) []libnetwork.Network {
    81  	c := daemon.netController
    82  	if c == nil {
    83  		return nil
    84  	}
    85  	list := []libnetwork.Network{}
    86  	l := func(nw libnetwork.Network) bool {
    87  		if strings.HasPrefix(nw.ID(), partialID) {
    88  			list = append(list, nw)
    89  		}
    90  		return false
    91  	}
    92  	c.WalkNetworks(l)
    93  
    94  	return list
    95  }
    96  
    97  // getAllNetworks returns a list containing all networks
    98  func (daemon *Daemon) getAllNetworks() []libnetwork.Network {
    99  	c := daemon.netController
   100  	list := []libnetwork.Network{}
   101  	l := func(nw libnetwork.Network) bool {
   102  		list = append(list, nw)
   103  		return false
   104  	}
   105  	c.WalkNetworks(l)
   106  
   107  	return list
   108  }
   109  
   110  func isIngressNetwork(name string) bool {
   111  	return name == "ingress"
   112  }
   113  
   114  var ingressChan = make(chan struct{}, 1)
   115  
   116  func ingressWait() func() {
   117  	ingressChan <- struct{}{}
   118  	return func() { <-ingressChan }
   119  }
   120  
   121  // SetupIngress setups ingress networking.
   122  func (daemon *Daemon) SetupIngress(create clustertypes.NetworkCreateRequest, nodeIP string) error {
   123  	ip, _, err := net.ParseCIDR(nodeIP)
   124  	if err != nil {
   125  		return err
   126  	}
   127  
   128  	go func() {
   129  		controller := daemon.netController
   130  		controller.AgentInitWait()
   131  
   132  		if n, err := daemon.GetNetworkByName(create.Name); err == nil && n != nil && n.ID() != create.ID {
   133  			if err := controller.SandboxDestroy("ingress-sbox"); err != nil {
   134  				logrus.Errorf("Failed to delete stale ingress sandbox: %v", err)
   135  				return
   136  			}
   137  
   138  			// Cleanup any stale endpoints that might be left over during previous iterations
   139  			epList := n.Endpoints()
   140  			for _, ep := range epList {
   141  				if err := ep.Delete(true); err != nil {
   142  					logrus.Errorf("Failed to delete endpoint %s (%s): %v", ep.Name(), ep.ID(), err)
   143  				}
   144  			}
   145  
   146  			if err := n.Delete(); err != nil {
   147  				logrus.Errorf("Failed to delete stale ingress network %s: %v", n.ID(), err)
   148  				return
   149  			}
   150  		}
   151  
   152  		if _, err := daemon.createNetwork(create.NetworkCreateRequest, create.ID, true); err != nil {
   153  			// If it is any other error other than already
   154  			// exists error log error and return.
   155  			if _, ok := err.(libnetwork.NetworkNameError); !ok {
   156  				logrus.Errorf("Failed creating ingress network: %v", err)
   157  				return
   158  			}
   159  
   160  			// Otherwise continue down the call to create or recreate sandbox.
   161  		}
   162  
   163  		n, err := daemon.GetNetworkByID(create.ID)
   164  		if err != nil {
   165  			logrus.Errorf("Failed getting ingress network by id after creating: %v", err)
   166  			return
   167  		}
   168  
   169  		sb, err := controller.NewSandbox("ingress-sbox", libnetwork.OptionIngress())
   170  		if err != nil {
   171  			if _, ok := err.(networktypes.ForbiddenError); !ok {
   172  				logrus.Errorf("Failed creating ingress sandbox: %v", err)
   173  			}
   174  			return
   175  		}
   176  
   177  		ep, err := n.CreateEndpoint("ingress-endpoint", libnetwork.CreateOptionIpam(ip, nil, nil, nil))
   178  		if err != nil {
   179  			logrus.Errorf("Failed creating ingress endpoint: %v", err)
   180  			return
   181  		}
   182  
   183  		if err := ep.Join(sb, nil); err != nil {
   184  			logrus.Errorf("Failed joining ingress sandbox to ingress endpoint: %v", err)
   185  		}
   186  
   187  		if err := sb.EnableService(); err != nil {
   188  			logrus.WithError(err).Error("Failed enabling service for ingress sandbox")
   189  		}
   190  	}()
   191  
   192  	return nil
   193  }
   194  
   195  // SetNetworkBootstrapKeys sets the bootstrap keys.
   196  func (daemon *Daemon) SetNetworkBootstrapKeys(keys []*networktypes.EncryptionKey) error {
   197  	return daemon.netController.SetKeys(keys)
   198  }
   199  
   200  // UpdateAttachment notifies the attacher about the attachment config.
   201  func (daemon *Daemon) UpdateAttachment(networkName, networkID, containerID string, config *network.NetworkingConfig) error {
   202  	if daemon.clusterProvider == nil {
   203  		return fmt.Errorf("cluster provider is not initialized")
   204  	}
   205  
   206  	if err := daemon.clusterProvider.UpdateAttachment(networkName, containerID, config); err != nil {
   207  		return daemon.clusterProvider.UpdateAttachment(networkID, containerID, config)
   208  	}
   209  
   210  	return nil
   211  }
   212  
   213  // WaitForDetachment makes the cluster manager wait for detachment of
   214  // the container from the network.
   215  func (daemon *Daemon) WaitForDetachment(ctx context.Context, networkName, networkID, taskID, containerID string) error {
   216  	if daemon.clusterProvider == nil {
   217  		return fmt.Errorf("cluster provider is not initialized")
   218  	}
   219  
   220  	return daemon.clusterProvider.WaitForDetachment(ctx, networkName, networkID, taskID, containerID)
   221  }
   222  
   223  // CreateManagedNetwork creates an agent network.
   224  func (daemon *Daemon) CreateManagedNetwork(create clustertypes.NetworkCreateRequest) error {
   225  	_, err := daemon.createNetwork(create.NetworkCreateRequest, create.ID, true)
   226  	return err
   227  }
   228  
   229  // CreateNetwork creates a network with the given name, driver and other optional parameters
   230  func (daemon *Daemon) CreateNetwork(create types.NetworkCreateRequest) (*types.NetworkCreateResponse, error) {
   231  	resp, err := daemon.createNetwork(create, "", false)
   232  	if err != nil {
   233  		return nil, err
   234  	}
   235  	return resp, err
   236  }
   237  
   238  func (daemon *Daemon) createNetwork(create types.NetworkCreateRequest, id string, agent bool) (*types.NetworkCreateResponse, error) {
   239  	// If there is a pending ingress network creation wait here
   240  	// since ingress network creation can happen via node download
   241  	// from manager or task download.
   242  	if isIngressNetwork(create.Name) {
   243  		defer ingressWait()()
   244  	}
   245  
   246  	if runconfig.IsPreDefinedNetwork(create.Name) && !agent {
   247  		err := fmt.Errorf("%s is a pre-defined network and cannot be created", create.Name)
   248  		return nil, apierrors.NewRequestForbiddenError(err)
   249  	}
   250  
   251  	var warning string
   252  	nw, err := daemon.GetNetworkByName(create.Name)
   253  	if err != nil {
   254  		if _, ok := err.(libnetwork.ErrNoSuchNetwork); !ok {
   255  			return nil, err
   256  		}
   257  	}
   258  	if nw != nil {
   259  		if create.CheckDuplicate {
   260  			return nil, libnetwork.NetworkNameError(create.Name)
   261  		}
   262  		warning = fmt.Sprintf("Network with name %s (id : %s) already exists", nw.Name(), nw.ID())
   263  	}
   264  
   265  	c := daemon.netController
   266  	driver := create.Driver
   267  	if driver == "" {
   268  		driver = c.Config().Daemon.DefaultDriver
   269  	}
   270  
   271  	nwOptions := []libnetwork.NetworkOption{
   272  		libnetwork.NetworkOptionEnableIPv6(create.EnableIPv6),
   273  		libnetwork.NetworkOptionDriverOpts(create.Options),
   274  		libnetwork.NetworkOptionLabels(create.Labels),
   275  		libnetwork.NetworkOptionAttachable(create.Attachable),
   276  	}
   277  
   278  	if create.IPAM != nil {
   279  		ipam := create.IPAM
   280  		v4Conf, v6Conf, err := getIpamConfig(ipam.Config)
   281  		if err != nil {
   282  			return nil, err
   283  		}
   284  		nwOptions = append(nwOptions, libnetwork.NetworkOptionIpam(ipam.Driver, "", v4Conf, v6Conf, ipam.Options))
   285  	}
   286  
   287  	if create.Internal {
   288  		nwOptions = append(nwOptions, libnetwork.NetworkOptionInternalNetwork())
   289  	}
   290  	if agent {
   291  		nwOptions = append(nwOptions, libnetwork.NetworkOptionDynamic())
   292  		nwOptions = append(nwOptions, libnetwork.NetworkOptionPersist(false))
   293  	}
   294  
   295  	if isIngressNetwork(create.Name) {
   296  		nwOptions = append(nwOptions, libnetwork.NetworkOptionIngress())
   297  	}
   298  
   299  	n, err := c.NewNetwork(driver, create.Name, id, nwOptions...)
   300  	if err != nil {
   301  		return nil, err
   302  	}
   303  
   304  	daemon.pluginRefCount(driver, driverapi.NetworkPluginEndpointType, plugingetter.ACQUIRE)
   305  	if create.IPAM != nil {
   306  		daemon.pluginRefCount(create.IPAM.Driver, ipamapi.PluginEndpointType, plugingetter.ACQUIRE)
   307  	}
   308  	daemon.LogNetworkEvent(n, "create")
   309  
   310  	return &types.NetworkCreateResponse{
   311  		ID:      n.ID(),
   312  		Warning: warning,
   313  	}, nil
   314  }
   315  
   316  func (daemon *Daemon) pluginRefCount(driver, capability string, mode int) {
   317  	var builtinDrivers []string
   318  
   319  	if capability == driverapi.NetworkPluginEndpointType {
   320  		builtinDrivers = daemon.netController.BuiltinDrivers()
   321  	} else if capability == ipamapi.PluginEndpointType {
   322  		builtinDrivers = daemon.netController.BuiltinIPAMDrivers()
   323  	}
   324  
   325  	for _, d := range builtinDrivers {
   326  		if d == driver {
   327  			return
   328  		}
   329  	}
   330  
   331  	if daemon.PluginStore != nil {
   332  		_, err := daemon.PluginStore.Get(driver, capability, mode)
   333  		if err != nil {
   334  			logrus.WithError(err).WithFields(logrus.Fields{"mode": mode, "driver": driver}).Error("Error handling plugin refcount operation")
   335  		}
   336  	}
   337  }
   338  
   339  func getIpamConfig(data []network.IPAMConfig) ([]*libnetwork.IpamConf, []*libnetwork.IpamConf, error) {
   340  	ipamV4Cfg := []*libnetwork.IpamConf{}
   341  	ipamV6Cfg := []*libnetwork.IpamConf{}
   342  	for _, d := range data {
   343  		iCfg := libnetwork.IpamConf{}
   344  		iCfg.PreferredPool = d.Subnet
   345  		iCfg.SubPool = d.IPRange
   346  		iCfg.Gateway = d.Gateway
   347  		iCfg.AuxAddresses = d.AuxAddress
   348  		ip, _, err := net.ParseCIDR(d.Subnet)
   349  		if err != nil {
   350  			return nil, nil, fmt.Errorf("Invalid subnet %s : %v", d.Subnet, err)
   351  		}
   352  		if ip.To4() != nil {
   353  			ipamV4Cfg = append(ipamV4Cfg, &iCfg)
   354  		} else {
   355  			ipamV6Cfg = append(ipamV6Cfg, &iCfg)
   356  		}
   357  	}
   358  	return ipamV4Cfg, ipamV6Cfg, nil
   359  }
   360  
   361  // UpdateContainerServiceConfig updates a service configuration.
   362  func (daemon *Daemon) UpdateContainerServiceConfig(containerName string, serviceConfig *clustertypes.ServiceConfig) error {
   363  	container, err := daemon.GetContainer(containerName)
   364  	if err != nil {
   365  		return err
   366  	}
   367  
   368  	container.NetworkSettings.Service = serviceConfig
   369  	return nil
   370  }
   371  
   372  // ConnectContainerToNetwork connects the given container to the given
   373  // network. If either cannot be found, an err is returned. If the
   374  // network cannot be set up, an err is returned.
   375  func (daemon *Daemon) ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error {
   376  	if runtime.GOOS == "solaris" {
   377  		return errors.New("docker network connect is unsupported on Solaris platform")
   378  	}
   379  	container, err := daemon.GetContainer(containerName)
   380  	if err != nil {
   381  		return err
   382  	}
   383  	return daemon.ConnectToNetwork(container, networkName, endpointConfig)
   384  }
   385  
   386  // DisconnectContainerFromNetwork disconnects the given container from
   387  // the given network. If either cannot be found, an err is returned.
   388  func (daemon *Daemon) DisconnectContainerFromNetwork(containerName string, networkName string, force bool) error {
   389  	if runtime.GOOS == "solaris" {
   390  		return errors.New("docker network disconnect is unsupported on Solaris platform")
   391  	}
   392  	container, err := daemon.GetContainer(containerName)
   393  	if err != nil {
   394  		if force {
   395  			return daemon.ForceEndpointDelete(containerName, networkName)
   396  		}
   397  		return err
   398  	}
   399  	return daemon.DisconnectFromNetwork(container, networkName, force)
   400  }
   401  
   402  // GetNetworkDriverList returns the list of plugins drivers
   403  // registered for network.
   404  func (daemon *Daemon) GetNetworkDriverList() []string {
   405  	if !daemon.NetworkControllerEnabled() {
   406  		return nil
   407  	}
   408  
   409  	pluginList := daemon.netController.BuiltinDrivers()
   410  
   411  	managedPlugins := daemon.PluginStore.GetAllManagedPluginsByCap(driverapi.NetworkPluginEndpointType)
   412  
   413  	for _, plugin := range managedPlugins {
   414  		pluginList = append(pluginList, plugin.Name())
   415  	}
   416  
   417  	pluginMap := make(map[string]bool)
   418  	for _, plugin := range pluginList {
   419  		pluginMap[plugin] = true
   420  	}
   421  
   422  	networks := daemon.netController.Networks()
   423  
   424  	for _, network := range networks {
   425  		if !pluginMap[network.Type()] {
   426  			pluginList = append(pluginList, network.Type())
   427  			pluginMap[network.Type()] = true
   428  		}
   429  	}
   430  
   431  	sort.Strings(pluginList)
   432  
   433  	return pluginList
   434  }
   435  
   436  // DeleteManagedNetwork deletes an agent network.
   437  func (daemon *Daemon) DeleteManagedNetwork(networkID string) error {
   438  	return daemon.deleteNetwork(networkID, true)
   439  }
   440  
   441  // DeleteNetwork destroys a network unless it's one of docker's predefined networks.
   442  func (daemon *Daemon) DeleteNetwork(networkID string) error {
   443  	return daemon.deleteNetwork(networkID, false)
   444  }
   445  
   446  func (daemon *Daemon) deleteNetwork(networkID string, dynamic bool) error {
   447  	nw, err := daemon.FindNetwork(networkID)
   448  	if err != nil {
   449  		return err
   450  	}
   451  
   452  	if runconfig.IsPreDefinedNetwork(nw.Name()) && !dynamic {
   453  		err := fmt.Errorf("%s is a pre-defined network and cannot be removed", nw.Name())
   454  		return apierrors.NewRequestForbiddenError(err)
   455  	}
   456  
   457  	if err := nw.Delete(); err != nil {
   458  		return err
   459  	}
   460  	daemon.pluginRefCount(nw.Type(), driverapi.NetworkPluginEndpointType, plugingetter.RELEASE)
   461  	ipamType, _, _, _ := nw.Info().IpamConfig()
   462  	daemon.pluginRefCount(ipamType, ipamapi.PluginEndpointType, plugingetter.RELEASE)
   463  	daemon.LogNetworkEvent(nw, "destroy")
   464  	return nil
   465  }
   466  
   467  // GetNetworks returns a list of all networks
   468  func (daemon *Daemon) GetNetworks() []libnetwork.Network {
   469  	return daemon.getAllNetworks()
   470  }