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