github.com/vincentwoo/docker@v0.7.3-0.20160116130405-82401a4b13c0/daemon/daemon_unix.go (about)

     1  // +build linux freebsd
     2  
     3  package daemon
     4  
     5  import (
     6  	"fmt"
     7  	"net"
     8  	"os"
     9  	"path/filepath"
    10  	"runtime"
    11  	"strconv"
    12  	"strings"
    13  	"syscall"
    14  
    15  	"github.com/Sirupsen/logrus"
    16  	"github.com/docker/docker/container"
    17  	derr "github.com/docker/docker/errors"
    18  	"github.com/docker/docker/image"
    19  	"github.com/docker/docker/layer"
    20  	"github.com/docker/docker/pkg/idtools"
    21  	"github.com/docker/docker/pkg/parsers/kernel"
    22  	"github.com/docker/docker/pkg/sysinfo"
    23  	"github.com/docker/docker/reference"
    24  	"github.com/docker/docker/runconfig"
    25  	runconfigopts "github.com/docker/docker/runconfig/opts"
    26  	pblkiodev "github.com/docker/engine-api/types/blkiodev"
    27  	containertypes "github.com/docker/engine-api/types/container"
    28  	"github.com/docker/libnetwork"
    29  	nwconfig "github.com/docker/libnetwork/config"
    30  	"github.com/docker/libnetwork/drivers/bridge"
    31  	"github.com/docker/libnetwork/ipamutils"
    32  	"github.com/docker/libnetwork/netlabel"
    33  	"github.com/docker/libnetwork/options"
    34  	"github.com/docker/libnetwork/types"
    35  	blkiodev "github.com/opencontainers/runc/libcontainer/configs"
    36  	"github.com/opencontainers/runc/libcontainer/label"
    37  	"github.com/opencontainers/runc/libcontainer/user"
    38  )
    39  
    40  const (
    41  	// See https://git.kernel.org/cgit/linux/kernel/git/tip/tip.git/tree/kernel/sched/sched.h?id=8cd9234c64c584432f6992fe944ca9e46ca8ea76#n269
    42  	linuxMinCPUShares = 2
    43  	linuxMaxCPUShares = 262144
    44  	platformSupported = true
    45  	// It's not kernel limit, we want this 4M limit to supply a reasonable functional container
    46  	linuxMinMemory = 4194304
    47  	// constants for remapped root settings
    48  	defaultIDSpecifier string = "default"
    49  	defaultRemappedID  string = "dockremap"
    50  )
    51  
    52  func getBlkioWeightDevices(config *containertypes.HostConfig) ([]*blkiodev.WeightDevice, error) {
    53  	var stat syscall.Stat_t
    54  	var blkioWeightDevices []*blkiodev.WeightDevice
    55  
    56  	for _, weightDevice := range config.BlkioWeightDevice {
    57  		if err := syscall.Stat(weightDevice.Path, &stat); err != nil {
    58  			return nil, err
    59  		}
    60  		weightDevice := blkiodev.NewWeightDevice(int64(stat.Rdev/256), int64(stat.Rdev%256), weightDevice.Weight, 0)
    61  		blkioWeightDevices = append(blkioWeightDevices, weightDevice)
    62  	}
    63  
    64  	return blkioWeightDevices, nil
    65  }
    66  
    67  func parseSecurityOpt(container *container.Container, config *containertypes.HostConfig) error {
    68  	var (
    69  		labelOpts []string
    70  		err       error
    71  	)
    72  
    73  	for _, opt := range config.SecurityOpt {
    74  		con := strings.SplitN(opt, ":", 2)
    75  		if len(con) == 1 {
    76  			return fmt.Errorf("Invalid --security-opt: %q", opt)
    77  		}
    78  		switch con[0] {
    79  		case "label":
    80  			labelOpts = append(labelOpts, con[1])
    81  		case "apparmor":
    82  			container.AppArmorProfile = con[1]
    83  		case "seccomp":
    84  			container.SeccompProfile = con[1]
    85  		default:
    86  			return fmt.Errorf("Invalid --security-opt: %q", opt)
    87  		}
    88  	}
    89  
    90  	container.ProcessLabel, container.MountLabel, err = label.InitLabels(labelOpts)
    91  	return err
    92  }
    93  
    94  func getBlkioReadIOpsDevices(config *containertypes.HostConfig) ([]*blkiodev.ThrottleDevice, error) {
    95  	var blkioReadIOpsDevice []*blkiodev.ThrottleDevice
    96  	var stat syscall.Stat_t
    97  
    98  	for _, iopsDevice := range config.BlkioDeviceReadIOps {
    99  		if err := syscall.Stat(iopsDevice.Path, &stat); err != nil {
   100  			return nil, err
   101  		}
   102  		readIOpsDevice := blkiodev.NewThrottleDevice(int64(stat.Rdev/256), int64(stat.Rdev%256), iopsDevice.Rate)
   103  		blkioReadIOpsDevice = append(blkioReadIOpsDevice, readIOpsDevice)
   104  	}
   105  
   106  	return blkioReadIOpsDevice, nil
   107  }
   108  
   109  func getBlkioWriteIOpsDevices(config *containertypes.HostConfig) ([]*blkiodev.ThrottleDevice, error) {
   110  	var blkioWriteIOpsDevice []*blkiodev.ThrottleDevice
   111  	var stat syscall.Stat_t
   112  
   113  	for _, iopsDevice := range config.BlkioDeviceWriteIOps {
   114  		if err := syscall.Stat(iopsDevice.Path, &stat); err != nil {
   115  			return nil, err
   116  		}
   117  		writeIOpsDevice := blkiodev.NewThrottleDevice(int64(stat.Rdev/256), int64(stat.Rdev%256), iopsDevice.Rate)
   118  		blkioWriteIOpsDevice = append(blkioWriteIOpsDevice, writeIOpsDevice)
   119  	}
   120  
   121  	return blkioWriteIOpsDevice, nil
   122  }
   123  
   124  func getBlkioReadBpsDevices(config *containertypes.HostConfig) ([]*blkiodev.ThrottleDevice, error) {
   125  	var blkioReadBpsDevice []*blkiodev.ThrottleDevice
   126  	var stat syscall.Stat_t
   127  
   128  	for _, bpsDevice := range config.BlkioDeviceReadBps {
   129  		if err := syscall.Stat(bpsDevice.Path, &stat); err != nil {
   130  			return nil, err
   131  		}
   132  		readBpsDevice := blkiodev.NewThrottleDevice(int64(stat.Rdev/256), int64(stat.Rdev%256), bpsDevice.Rate)
   133  		blkioReadBpsDevice = append(blkioReadBpsDevice, readBpsDevice)
   134  	}
   135  
   136  	return blkioReadBpsDevice, nil
   137  }
   138  
   139  func getBlkioWriteBpsDevices(config *containertypes.HostConfig) ([]*blkiodev.ThrottleDevice, error) {
   140  	var blkioWriteBpsDevice []*blkiodev.ThrottleDevice
   141  	var stat syscall.Stat_t
   142  
   143  	for _, bpsDevice := range config.BlkioDeviceWriteBps {
   144  		if err := syscall.Stat(bpsDevice.Path, &stat); err != nil {
   145  			return nil, err
   146  		}
   147  		writeBpsDevice := blkiodev.NewThrottleDevice(int64(stat.Rdev/256), int64(stat.Rdev%256), bpsDevice.Rate)
   148  		blkioWriteBpsDevice = append(blkioWriteBpsDevice, writeBpsDevice)
   149  	}
   150  
   151  	return blkioWriteBpsDevice, nil
   152  }
   153  
   154  func checkKernelVersion(k, major, minor int) bool {
   155  	if v, err := kernel.GetKernelVersion(); err != nil {
   156  		logrus.Warnf("%s", err)
   157  	} else {
   158  		if kernel.CompareKernelVersion(*v, kernel.VersionInfo{Kernel: k, Major: major, Minor: minor}) < 0 {
   159  			return false
   160  		}
   161  	}
   162  	return true
   163  }
   164  
   165  func checkKernel() error {
   166  	// Check for unsupported kernel versions
   167  	// FIXME: it would be cleaner to not test for specific versions, but rather
   168  	// test for specific functionalities.
   169  	// Unfortunately we can't test for the feature "does not cause a kernel panic"
   170  	// without actually causing a kernel panic, so we need this workaround until
   171  	// the circumstances of pre-3.10 crashes are clearer.
   172  	// For details see https://github.com/docker/docker/issues/407
   173  	if !checkKernelVersion(3, 10, 0) {
   174  		v, _ := kernel.GetKernelVersion()
   175  		if os.Getenv("DOCKER_NOWARN_KERNEL_VERSION") == "" {
   176  			logrus.Warnf("Your Linux kernel version %s can be unstable running docker. Please upgrade your kernel to 3.10.0.", v.String())
   177  		}
   178  	}
   179  	return nil
   180  }
   181  
   182  // adaptContainerSettings is called during container creation to modify any
   183  // settings necessary in the HostConfig structure.
   184  func (daemon *Daemon) adaptContainerSettings(hostConfig *containertypes.HostConfig, adjustCPUShares bool) error {
   185  	if adjustCPUShares && hostConfig.CPUShares > 0 {
   186  		// Handle unsupported CPUShares
   187  		if hostConfig.CPUShares < linuxMinCPUShares {
   188  			logrus.Warnf("Changing requested CPUShares of %d to minimum allowed of %d", hostConfig.CPUShares, linuxMinCPUShares)
   189  			hostConfig.CPUShares = linuxMinCPUShares
   190  		} else if hostConfig.CPUShares > linuxMaxCPUShares {
   191  			logrus.Warnf("Changing requested CPUShares of %d to maximum allowed of %d", hostConfig.CPUShares, linuxMaxCPUShares)
   192  			hostConfig.CPUShares = linuxMaxCPUShares
   193  		}
   194  	}
   195  	if hostConfig.Memory > 0 && hostConfig.MemorySwap == 0 {
   196  		// By default, MemorySwap is set to twice the size of Memory.
   197  		hostConfig.MemorySwap = hostConfig.Memory * 2
   198  	}
   199  	if hostConfig.ShmSize == 0 {
   200  		hostConfig.ShmSize = container.DefaultSHMSize
   201  	}
   202  	var err error
   203  	if hostConfig.SecurityOpt == nil {
   204  		hostConfig.SecurityOpt, err = daemon.generateSecurityOpt(hostConfig.IpcMode, hostConfig.PidMode)
   205  		if err != nil {
   206  			return err
   207  		}
   208  	}
   209  	if hostConfig.MemorySwappiness == nil {
   210  		defaultSwappiness := int64(-1)
   211  		hostConfig.MemorySwappiness = &defaultSwappiness
   212  	}
   213  	if hostConfig.OomKillDisable == nil {
   214  		defaultOomKillDisable := false
   215  		hostConfig.OomKillDisable = &defaultOomKillDisable
   216  	}
   217  
   218  	return nil
   219  }
   220  
   221  func verifyContainerResources(resources *containertypes.Resources) ([]string, error) {
   222  	warnings := []string{}
   223  	sysInfo := sysinfo.New(true)
   224  
   225  	// memory subsystem checks and adjustments
   226  	if resources.Memory != 0 && resources.Memory < linuxMinMemory {
   227  		return warnings, fmt.Errorf("Minimum memory limit allowed is 4MB")
   228  	}
   229  	if resources.Memory > 0 && !sysInfo.MemoryLimit {
   230  		warnings = append(warnings, "Your kernel does not support memory limit capabilities. Limitation discarded.")
   231  		logrus.Warnf("Your kernel does not support memory limit capabilities. Limitation discarded.")
   232  		resources.Memory = 0
   233  		resources.MemorySwap = -1
   234  	}
   235  	if resources.Memory > 0 && resources.MemorySwap != -1 && !sysInfo.SwapLimit {
   236  		warnings = append(warnings, "Your kernel does not support swap limit capabilities, memory limited without swap.")
   237  		logrus.Warnf("Your kernel does not support swap limit capabilities, memory limited without swap.")
   238  		resources.MemorySwap = -1
   239  	}
   240  	if resources.Memory > 0 && resources.MemorySwap > 0 && resources.MemorySwap < resources.Memory {
   241  		return warnings, fmt.Errorf("Minimum memoryswap limit should be larger than memory limit, see usage.")
   242  	}
   243  	if resources.Memory == 0 && resources.MemorySwap > 0 {
   244  		return warnings, fmt.Errorf("You should always set the Memory limit when using Memoryswap limit, see usage.")
   245  	}
   246  	if resources.MemorySwappiness != nil && *resources.MemorySwappiness != -1 && !sysInfo.MemorySwappiness {
   247  		warnings = append(warnings, "Your kernel does not support memory swappiness capabilities, memory swappiness discarded.")
   248  		logrus.Warnf("Your kernel does not support memory swappiness capabilities, memory swappiness discarded.")
   249  		resources.MemorySwappiness = nil
   250  	}
   251  	if resources.MemorySwappiness != nil {
   252  		swappiness := *resources.MemorySwappiness
   253  		if swappiness < -1 || swappiness > 100 {
   254  			return warnings, fmt.Errorf("Invalid value: %v, valid memory swappiness range is 0-100.", swappiness)
   255  		}
   256  	}
   257  	if resources.MemoryReservation > 0 && !sysInfo.MemoryReservation {
   258  		warnings = append(warnings, "Your kernel does not support memory soft limit capabilities. Limitation discarded.")
   259  		logrus.Warnf("Your kernel does not support memory soft limit capabilities. Limitation discarded.")
   260  		resources.MemoryReservation = 0
   261  	}
   262  	if resources.Memory > 0 && resources.MemoryReservation > 0 && resources.Memory < resources.MemoryReservation {
   263  		return warnings, fmt.Errorf("Minimum memory limit should be larger than memory reservation limit, see usage.")
   264  	}
   265  	if resources.KernelMemory > 0 && !sysInfo.KernelMemory {
   266  		warnings = append(warnings, "Your kernel does not support kernel memory limit capabilities. Limitation discarded.")
   267  		logrus.Warnf("Your kernel does not support kernel memory limit capabilities. Limitation discarded.")
   268  		resources.KernelMemory = 0
   269  	}
   270  	if resources.KernelMemory > 0 && resources.KernelMemory < linuxMinMemory {
   271  		return warnings, fmt.Errorf("Minimum kernel memory limit allowed is 4MB")
   272  	}
   273  	if resources.KernelMemory > 0 && !checkKernelVersion(4, 0, 0) {
   274  		warnings = append(warnings, "You specified a kernel memory limit on a kernel older than 4.0. Kernel memory limits are experimental on older kernels, it won't work as expected and can cause your system to be unstable.")
   275  		logrus.Warnf("You specified a kernel memory limit on a kernel older than 4.0. Kernel memory limits are experimental on older kernels, it won't work as expected and can cause your system to be unstable.")
   276  	}
   277  	if resources.OomKillDisable != nil && !sysInfo.OomKillDisable {
   278  		// only produce warnings if the setting wasn't to *disable* the OOM Kill; no point
   279  		// warning the caller if they already wanted the feature to be off
   280  		if *resources.OomKillDisable {
   281  			warnings = append(warnings, "Your kernel does not support OomKillDisable, OomKillDisable discarded.")
   282  			logrus.Warnf("Your kernel does not support OomKillDisable, OomKillDisable discarded.")
   283  		}
   284  		resources.OomKillDisable = nil
   285  	}
   286  
   287  	// cpu subsystem checks and adjustments
   288  	if resources.CPUShares > 0 && !sysInfo.CPUShares {
   289  		warnings = append(warnings, "Your kernel does not support CPU shares. Shares discarded.")
   290  		logrus.Warnf("Your kernel does not support CPU shares. Shares discarded.")
   291  		resources.CPUShares = 0
   292  	}
   293  	if resources.CPUPeriod > 0 && !sysInfo.CPUCfsPeriod {
   294  		warnings = append(warnings, "Your kernel does not support CPU cfs period. Period discarded.")
   295  		logrus.Warnf("Your kernel does not support CPU cfs period. Period discarded.")
   296  		resources.CPUPeriod = 0
   297  	}
   298  	if resources.CPUQuota > 0 && !sysInfo.CPUCfsQuota {
   299  		warnings = append(warnings, "Your kernel does not support CPU cfs quota. Quota discarded.")
   300  		logrus.Warnf("Your kernel does not support CPU cfs quota. Quota discarded.")
   301  		resources.CPUQuota = 0
   302  	}
   303  
   304  	// cpuset subsystem checks and adjustments
   305  	if (resources.CpusetCpus != "" || resources.CpusetMems != "") && !sysInfo.Cpuset {
   306  		warnings = append(warnings, "Your kernel does not support cpuset. Cpuset discarded.")
   307  		logrus.Warnf("Your kernel does not support cpuset. Cpuset discarded.")
   308  		resources.CpusetCpus = ""
   309  		resources.CpusetMems = ""
   310  	}
   311  	cpusAvailable, err := sysInfo.IsCpusetCpusAvailable(resources.CpusetCpus)
   312  	if err != nil {
   313  		return warnings, derr.ErrorCodeInvalidCpusetCpus.WithArgs(resources.CpusetCpus)
   314  	}
   315  	if !cpusAvailable {
   316  		return warnings, derr.ErrorCodeNotAvailableCpusetCpus.WithArgs(resources.CpusetCpus, sysInfo.Cpus)
   317  	}
   318  	memsAvailable, err := sysInfo.IsCpusetMemsAvailable(resources.CpusetMems)
   319  	if err != nil {
   320  		return warnings, derr.ErrorCodeInvalidCpusetMems.WithArgs(resources.CpusetMems)
   321  	}
   322  	if !memsAvailable {
   323  		return warnings, derr.ErrorCodeNotAvailableCpusetMems.WithArgs(resources.CpusetMems, sysInfo.Mems)
   324  	}
   325  
   326  	// blkio subsystem checks and adjustments
   327  	if resources.BlkioWeight > 0 && !sysInfo.BlkioWeight {
   328  		warnings = append(warnings, "Your kernel does not support Block I/O weight. Weight discarded.")
   329  		logrus.Warnf("Your kernel does not support Block I/O weight. Weight discarded.")
   330  		resources.BlkioWeight = 0
   331  	}
   332  	if resources.BlkioWeight > 0 && (resources.BlkioWeight < 10 || resources.BlkioWeight > 1000) {
   333  		return warnings, fmt.Errorf("Range of blkio weight is from 10 to 1000.")
   334  	}
   335  	if len(resources.BlkioWeightDevice) > 0 && !sysInfo.BlkioWeightDevice {
   336  		warnings = append(warnings, "Your kernel does not support Block I/O weight_device.")
   337  		logrus.Warnf("Your kernel does not support Block I/O weight_device. Weight-device discarded.")
   338  		resources.BlkioWeightDevice = []*pblkiodev.WeightDevice{}
   339  	}
   340  	if len(resources.BlkioDeviceReadBps) > 0 && !sysInfo.BlkioReadBpsDevice {
   341  		warnings = append(warnings, "Your kernel does not support Block read limit in bytes per second.")
   342  		logrus.Warnf("Your kernel does not support Block I/O read limit in bytes per second. --device-read-bps discarded.")
   343  		resources.BlkioDeviceReadBps = []*pblkiodev.ThrottleDevice{}
   344  	}
   345  	if len(resources.BlkioDeviceWriteBps) > 0 && !sysInfo.BlkioWriteBpsDevice {
   346  		warnings = append(warnings, "Your kernel does not support Block write limit in bytes per second.")
   347  		logrus.Warnf("Your kernel does not support Block I/O write limit in bytes per second. --device-write-bps discarded.")
   348  		resources.BlkioDeviceWriteBps = []*pblkiodev.ThrottleDevice{}
   349  	}
   350  	if len(resources.BlkioDeviceReadIOps) > 0 && !sysInfo.BlkioReadIOpsDevice {
   351  		warnings = append(warnings, "Your kernel does not support Block read limit in IO per second.")
   352  		logrus.Warnf("Your kernel does not support Block I/O read limit in IO per second. -device-read-iops discarded.")
   353  		resources.BlkioDeviceReadIOps = []*pblkiodev.ThrottleDevice{}
   354  	}
   355  	if len(resources.BlkioDeviceWriteIOps) > 0 && !sysInfo.BlkioWriteIOpsDevice {
   356  		warnings = append(warnings, "Your kernel does not support Block write limit in IO per second.")
   357  		logrus.Warnf("Your kernel does not support Block I/O write limit in IO per second. --device-write-iops discarded.")
   358  		resources.BlkioDeviceWriteIOps = []*pblkiodev.ThrottleDevice{}
   359  	}
   360  
   361  	return warnings, nil
   362  }
   363  
   364  // verifyPlatformContainerSettings performs platform-specific validation of the
   365  // hostconfig and config structures.
   366  func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.HostConfig, config *containertypes.Config) ([]string, error) {
   367  	warnings := []string{}
   368  	sysInfo := sysinfo.New(true)
   369  
   370  	warnings, err := daemon.verifyExperimentalContainerSettings(hostConfig, config)
   371  	if err != nil {
   372  		return warnings, err
   373  	}
   374  
   375  	w, err := verifyContainerResources(&hostConfig.Resources)
   376  	if err != nil {
   377  		return warnings, err
   378  	}
   379  	warnings = append(warnings, w...)
   380  
   381  	if hostConfig.ShmSize < 0 {
   382  		return warnings, fmt.Errorf("SHM size must be greater then 0")
   383  	}
   384  
   385  	if hostConfig.OomScoreAdj < -1000 || hostConfig.OomScoreAdj > 1000 {
   386  		return warnings, fmt.Errorf("Invalid value %d, range for oom score adj is [-1000, 1000].", hostConfig.OomScoreAdj)
   387  	}
   388  	if sysInfo.IPv4ForwardingDisabled {
   389  		warnings = append(warnings, "IPv4 forwarding is disabled. Networking will not work.")
   390  		logrus.Warnf("IPv4 forwarding is disabled. Networking will not work")
   391  	}
   392  	// check for various conflicting options with user namespaces
   393  	if daemon.configStore.RemappedRoot != "" {
   394  		if hostConfig.Privileged {
   395  			return warnings, fmt.Errorf("Privileged mode is incompatible with user namespaces.")
   396  		}
   397  		if hostConfig.NetworkMode.IsHost() || hostConfig.NetworkMode.IsContainer() {
   398  			return warnings, fmt.Errorf("Cannot share the host or a container's network namespace when user namespaces are enabled.")
   399  		}
   400  		if hostConfig.PidMode.IsHost() {
   401  			return warnings, fmt.Errorf("Cannot share the host PID namespace when user namespaces are enabled.")
   402  		}
   403  		if hostConfig.IpcMode.IsContainer() {
   404  			return warnings, fmt.Errorf("Cannot share a container's IPC namespace when user namespaces are enabled.")
   405  		}
   406  		if hostConfig.ReadonlyRootfs {
   407  			return warnings, fmt.Errorf("Cannot use the --read-only option when user namespaces are enabled.")
   408  		}
   409  	}
   410  	return warnings, nil
   411  }
   412  
   413  // checkConfigOptions checks for mutually incompatible config options
   414  func checkConfigOptions(config *Config) error {
   415  	// Check for mutually incompatible config options
   416  	if config.Bridge.Iface != "" && config.Bridge.IP != "" {
   417  		return fmt.Errorf("You specified -b & --bip, mutually exclusive options. Please specify only one.")
   418  	}
   419  	if !config.Bridge.EnableIPTables && !config.Bridge.InterContainerCommunication {
   420  		return fmt.Errorf("You specified --iptables=false with --icc=false. ICC=false uses iptables to function. Please set --icc or --iptables to true.")
   421  	}
   422  	if !config.Bridge.EnableIPTables && config.Bridge.EnableIPMasq {
   423  		config.Bridge.EnableIPMasq = false
   424  	}
   425  	return nil
   426  }
   427  
   428  // checkSystem validates platform-specific requirements
   429  func checkSystem() error {
   430  	if os.Geteuid() != 0 {
   431  		return fmt.Errorf("The Docker daemon needs to be run as root")
   432  	}
   433  	return checkKernel()
   434  }
   435  
   436  // configureKernelSecuritySupport configures and validate security support for the kernel
   437  func configureKernelSecuritySupport(config *Config, driverName string) error {
   438  	if config.EnableSelinuxSupport {
   439  		if selinuxEnabled() {
   440  			// As Docker on overlayFS and SELinux are incompatible at present, error on overlayfs being enabled
   441  			if driverName == "overlay" {
   442  				return fmt.Errorf("SELinux is not supported with the %s graph driver", driverName)
   443  			}
   444  			logrus.Debug("SELinux enabled successfully")
   445  		} else {
   446  			logrus.Warn("Docker could not enable SELinux on the host system")
   447  		}
   448  	} else {
   449  		selinuxSetDisabled()
   450  	}
   451  	return nil
   452  }
   453  
   454  func isBridgeNetworkDisabled(config *Config) bool {
   455  	return config.Bridge.Iface == disableNetworkBridge
   456  }
   457  
   458  func (daemon *Daemon) networkOptions(dconfig *Config) ([]nwconfig.Option, error) {
   459  	options := []nwconfig.Option{}
   460  	if dconfig == nil {
   461  		return options, nil
   462  	}
   463  
   464  	options = append(options, nwconfig.OptionDataDir(dconfig.Root))
   465  
   466  	dd := runconfig.DefaultDaemonNetworkMode()
   467  	dn := runconfig.DefaultDaemonNetworkMode().NetworkName()
   468  	options = append(options, nwconfig.OptionDefaultDriver(string(dd)))
   469  	options = append(options, nwconfig.OptionDefaultNetwork(dn))
   470  
   471  	if strings.TrimSpace(dconfig.ClusterStore) != "" {
   472  		kv := strings.Split(dconfig.ClusterStore, "://")
   473  		if len(kv) != 2 {
   474  			return nil, fmt.Errorf("kv store daemon config must be of the form KV-PROVIDER://KV-URL")
   475  		}
   476  		options = append(options, nwconfig.OptionKVProvider(kv[0]))
   477  		options = append(options, nwconfig.OptionKVProviderURL(kv[1]))
   478  	}
   479  	if len(dconfig.ClusterOpts) > 0 {
   480  		options = append(options, nwconfig.OptionKVOpts(dconfig.ClusterOpts))
   481  	}
   482  
   483  	if daemon.discoveryWatcher != nil {
   484  		options = append(options, nwconfig.OptionDiscoveryWatcher(daemon.discoveryWatcher))
   485  	}
   486  
   487  	if dconfig.ClusterAdvertise != "" {
   488  		options = append(options, nwconfig.OptionDiscoveryAddress(dconfig.ClusterAdvertise))
   489  	}
   490  
   491  	options = append(options, nwconfig.OptionLabels(dconfig.Labels))
   492  	options = append(options, driverOptions(dconfig)...)
   493  	return options, nil
   494  }
   495  
   496  func (daemon *Daemon) initNetworkController(config *Config) (libnetwork.NetworkController, error) {
   497  	netOptions, err := daemon.networkOptions(config)
   498  	if err != nil {
   499  		return nil, err
   500  	}
   501  
   502  	controller, err := libnetwork.New(netOptions...)
   503  	if err != nil {
   504  		return nil, fmt.Errorf("error obtaining controller instance: %v", err)
   505  	}
   506  
   507  	// Initialize default network on "null"
   508  	if _, err := controller.NewNetwork("null", "none", libnetwork.NetworkOptionPersist(false)); err != nil {
   509  		return nil, fmt.Errorf("Error creating default \"null\" network: %v", err)
   510  	}
   511  
   512  	// Initialize default network on "host"
   513  	if _, err := controller.NewNetwork("host", "host", libnetwork.NetworkOptionPersist(false)); err != nil {
   514  		return nil, fmt.Errorf("Error creating default \"host\" network: %v", err)
   515  	}
   516  
   517  	if !config.DisableBridge {
   518  		// Initialize default driver "bridge"
   519  		if err := initBridgeDriver(controller, config); err != nil {
   520  			return nil, err
   521  		}
   522  	}
   523  
   524  	return controller, nil
   525  }
   526  
   527  func driverOptions(config *Config) []nwconfig.Option {
   528  	bridgeConfig := options.Generic{
   529  		"EnableIPForwarding":  config.Bridge.EnableIPForward,
   530  		"EnableIPTables":      config.Bridge.EnableIPTables,
   531  		"EnableUserlandProxy": config.Bridge.EnableUserlandProxy}
   532  	bridgeOption := options.Generic{netlabel.GenericData: bridgeConfig}
   533  
   534  	dOptions := []nwconfig.Option{}
   535  	dOptions = append(dOptions, nwconfig.OptionDriverConfig("bridge", bridgeOption))
   536  	return dOptions
   537  }
   538  
   539  func initBridgeDriver(controller libnetwork.NetworkController, config *Config) error {
   540  	if n, err := controller.NetworkByName("bridge"); err == nil {
   541  		if err = n.Delete(); err != nil {
   542  			return fmt.Errorf("could not delete the default bridge network: %v", err)
   543  		}
   544  	}
   545  
   546  	bridgeName := bridge.DefaultBridgeName
   547  	if config.Bridge.Iface != "" {
   548  		bridgeName = config.Bridge.Iface
   549  	}
   550  	netOption := map[string]string{
   551  		bridge.BridgeName:         bridgeName,
   552  		bridge.DefaultBridge:      strconv.FormatBool(true),
   553  		netlabel.DriverMTU:        strconv.Itoa(config.Mtu),
   554  		bridge.EnableIPMasquerade: strconv.FormatBool(config.Bridge.EnableIPMasq),
   555  		bridge.EnableICC:          strconv.FormatBool(config.Bridge.InterContainerCommunication),
   556  	}
   557  
   558  	// --ip processing
   559  	if config.Bridge.DefaultIP != nil {
   560  		netOption[bridge.DefaultBindingIP] = config.Bridge.DefaultIP.String()
   561  	}
   562  
   563  	var (
   564  		ipamV4Conf *libnetwork.IpamConf
   565  		ipamV6Conf *libnetwork.IpamConf
   566  	)
   567  
   568  	ipamV4Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)}
   569  
   570  	nw, nw6List, err := ipamutils.ElectInterfaceAddresses(bridgeName)
   571  	if err == nil {
   572  		ipamV4Conf.PreferredPool = types.GetIPNetCanonical(nw).String()
   573  		hip, _ := types.GetHostPartIP(nw.IP, nw.Mask)
   574  		if hip.IsGlobalUnicast() {
   575  			ipamV4Conf.Gateway = nw.IP.String()
   576  		}
   577  	}
   578  
   579  	if config.Bridge.IP != "" {
   580  		ipamV4Conf.PreferredPool = config.Bridge.IP
   581  		ip, _, err := net.ParseCIDR(config.Bridge.IP)
   582  		if err != nil {
   583  			return err
   584  		}
   585  		ipamV4Conf.Gateway = ip.String()
   586  	} else if bridgeName == bridge.DefaultBridgeName && ipamV4Conf.PreferredPool != "" {
   587  		logrus.Infof("Default bridge (%s) is assigned with an IP address %s. Daemon option --bip can be used to set a preferred IP address", bridgeName, ipamV4Conf.PreferredPool)
   588  	}
   589  
   590  	if config.Bridge.FixedCIDR != "" {
   591  		_, fCIDR, err := net.ParseCIDR(config.Bridge.FixedCIDR)
   592  		if err != nil {
   593  			return err
   594  		}
   595  
   596  		ipamV4Conf.SubPool = fCIDR.String()
   597  	}
   598  
   599  	if config.Bridge.DefaultGatewayIPv4 != nil {
   600  		ipamV4Conf.AuxAddresses["DefaultGatewayIPv4"] = config.Bridge.DefaultGatewayIPv4.String()
   601  	}
   602  
   603  	var deferIPv6Alloc bool
   604  	if config.Bridge.FixedCIDRv6 != "" {
   605  		_, fCIDRv6, err := net.ParseCIDR(config.Bridge.FixedCIDRv6)
   606  		if err != nil {
   607  			return err
   608  		}
   609  
   610  		// In case user has specified the daemon flag --fixed-cidr-v6 and the passed network has
   611  		// at least 48 host bits, we need to guarantee the current behavior where the containers'
   612  		// IPv6 addresses will be constructed based on the containers' interface MAC address.
   613  		// We do so by telling libnetwork to defer the IPv6 address allocation for the endpoints
   614  		// on this network until after the driver has created the endpoint and returned the
   615  		// constructed address. Libnetwork will then reserve this address with the ipam driver.
   616  		ones, _ := fCIDRv6.Mask.Size()
   617  		deferIPv6Alloc = ones <= 80
   618  
   619  		if ipamV6Conf == nil {
   620  			ipamV6Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)}
   621  		}
   622  		ipamV6Conf.PreferredPool = fCIDRv6.String()
   623  
   624  		// In case the --fixed-cidr-v6 is specified and the current docker0 bridge IPv6
   625  		// address belongs to the same network, we need to inform libnetwork about it, so
   626  		// that it can be reserved with IPAM and it will not be given away to somebody else
   627  		for _, nw6 := range nw6List {
   628  			if fCIDRv6.Contains(nw6.IP) {
   629  				ipamV6Conf.Gateway = nw6.IP.String()
   630  				break
   631  			}
   632  		}
   633  	}
   634  
   635  	if config.Bridge.DefaultGatewayIPv6 != nil {
   636  		if ipamV6Conf == nil {
   637  			ipamV6Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)}
   638  		}
   639  		ipamV6Conf.AuxAddresses["DefaultGatewayIPv6"] = config.Bridge.DefaultGatewayIPv6.String()
   640  	}
   641  
   642  	v4Conf := []*libnetwork.IpamConf{ipamV4Conf}
   643  	v6Conf := []*libnetwork.IpamConf{}
   644  	if ipamV6Conf != nil {
   645  		v6Conf = append(v6Conf, ipamV6Conf)
   646  	}
   647  	// Initialize default network on "bridge" with the same name
   648  	_, err = controller.NewNetwork("bridge", "bridge",
   649  		libnetwork.NetworkOptionGeneric(options.Generic{
   650  			netlabel.GenericData: netOption,
   651  			netlabel.EnableIPv6:  config.Bridge.EnableIPv6,
   652  		}),
   653  		libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil),
   654  		libnetwork.NetworkOptionDeferIPv6Alloc(deferIPv6Alloc))
   655  	if err != nil {
   656  		return fmt.Errorf("Error creating default \"bridge\" network: %v", err)
   657  	}
   658  	return nil
   659  }
   660  
   661  // setupInitLayer populates a directory with mountpoints suitable
   662  // for bind-mounting dockerinit into the container. The mountpoint is simply an
   663  // empty file at /.dockerinit
   664  //
   665  // This extra layer is used by all containers as the top-most ro layer. It protects
   666  // the container from unwanted side-effects on the rw layer.
   667  func setupInitLayer(initLayer string, rootUID, rootGID int) error {
   668  	for pth, typ := range map[string]string{
   669  		"/dev/pts":         "dir",
   670  		"/dev/shm":         "dir",
   671  		"/proc":            "dir",
   672  		"/sys":             "dir",
   673  		"/.dockerinit":     "file",
   674  		"/.dockerenv":      "file",
   675  		"/etc/resolv.conf": "file",
   676  		"/etc/hosts":       "file",
   677  		"/etc/hostname":    "file",
   678  		"/dev/console":     "file",
   679  		"/etc/mtab":        "/proc/mounts",
   680  	} {
   681  		parts := strings.Split(pth, "/")
   682  		prev := "/"
   683  		for _, p := range parts[1:] {
   684  			prev = filepath.Join(prev, p)
   685  			syscall.Unlink(filepath.Join(initLayer, prev))
   686  		}
   687  
   688  		if _, err := os.Stat(filepath.Join(initLayer, pth)); err != nil {
   689  			if os.IsNotExist(err) {
   690  				if err := idtools.MkdirAllNewAs(filepath.Join(initLayer, filepath.Dir(pth)), 0755, rootUID, rootGID); err != nil {
   691  					return err
   692  				}
   693  				switch typ {
   694  				case "dir":
   695  					if err := idtools.MkdirAllNewAs(filepath.Join(initLayer, pth), 0755, rootUID, rootGID); err != nil {
   696  						return err
   697  					}
   698  				case "file":
   699  					f, err := os.OpenFile(filepath.Join(initLayer, pth), os.O_CREATE, 0755)
   700  					if err != nil {
   701  						return err
   702  					}
   703  					f.Chown(rootUID, rootGID)
   704  					f.Close()
   705  				default:
   706  					if err := os.Symlink(typ, filepath.Join(initLayer, pth)); err != nil {
   707  						return err
   708  					}
   709  				}
   710  			} else {
   711  				return err
   712  			}
   713  		}
   714  	}
   715  
   716  	// Layer is ready to use, if it wasn't before.
   717  	return nil
   718  }
   719  
   720  // Parse the remapped root (user namespace) option, which can be one of:
   721  //   username            - valid username from /etc/passwd
   722  //   username:groupname  - valid username; valid groupname from /etc/group
   723  //   uid                 - 32-bit unsigned int valid Linux UID value
   724  //   uid:gid             - uid value; 32-bit unsigned int Linux GID value
   725  //
   726  //  If no groupname is specified, and a username is specified, an attempt
   727  //  will be made to lookup a gid for that username as a groupname
   728  //
   729  //  If names are used, they are verified to exist in passwd/group
   730  func parseRemappedRoot(usergrp string) (string, string, error) {
   731  
   732  	var (
   733  		userID, groupID     int
   734  		username, groupname string
   735  	)
   736  
   737  	idparts := strings.Split(usergrp, ":")
   738  	if len(idparts) > 2 {
   739  		return "", "", fmt.Errorf("Invalid user/group specification in --userns-remap: %q", usergrp)
   740  	}
   741  
   742  	if uid, err := strconv.ParseInt(idparts[0], 10, 32); err == nil {
   743  		// must be a uid; take it as valid
   744  		userID = int(uid)
   745  		luser, err := user.LookupUid(userID)
   746  		if err != nil {
   747  			return "", "", fmt.Errorf("Uid %d has no entry in /etc/passwd: %v", userID, err)
   748  		}
   749  		username = luser.Name
   750  		if len(idparts) == 1 {
   751  			// if the uid was numeric and no gid was specified, take the uid as the gid
   752  			groupID = userID
   753  			lgrp, err := user.LookupGid(groupID)
   754  			if err != nil {
   755  				return "", "", fmt.Errorf("Gid %d has no entry in /etc/group: %v", groupID, err)
   756  			}
   757  			groupname = lgrp.Name
   758  		}
   759  	} else {
   760  		lookupName := idparts[0]
   761  		// special case: if the user specified "default", they want Docker to create or
   762  		// use (after creation) the "dockremap" user/group for root remapping
   763  		if lookupName == defaultIDSpecifier {
   764  			lookupName = defaultRemappedID
   765  		}
   766  		luser, err := user.LookupUser(lookupName)
   767  		if err != nil && idparts[0] != defaultIDSpecifier {
   768  			// error if the name requested isn't the special "dockremap" ID
   769  			return "", "", fmt.Errorf("Error during uid lookup for %q: %v", lookupName, err)
   770  		} else if err != nil {
   771  			// special case-- if the username == "default", then we have been asked
   772  			// to create a new entry pair in /etc/{passwd,group} for which the /etc/sub{uid,gid}
   773  			// ranges will be used for the user and group mappings in user namespaced containers
   774  			_, _, err := idtools.AddNamespaceRangesUser(defaultRemappedID)
   775  			if err == nil {
   776  				return defaultRemappedID, defaultRemappedID, nil
   777  			}
   778  			return "", "", fmt.Errorf("Error during %q user creation: %v", defaultRemappedID, err)
   779  		}
   780  		userID = luser.Uid
   781  		username = luser.Name
   782  		if len(idparts) == 1 {
   783  			// we only have a string username, and no group specified; look up gid from username as group
   784  			group, err := user.LookupGroup(lookupName)
   785  			if err != nil {
   786  				return "", "", fmt.Errorf("Error during gid lookup for %q: %v", lookupName, err)
   787  			}
   788  			groupID = group.Gid
   789  			groupname = group.Name
   790  		}
   791  	}
   792  
   793  	if len(idparts) == 2 {
   794  		// groupname or gid is separately specified and must be resolved
   795  		// to a unsigned 32-bit gid
   796  		if gid, err := strconv.ParseInt(idparts[1], 10, 32); err == nil {
   797  			// must be a gid, take it as valid
   798  			groupID = int(gid)
   799  			lgrp, err := user.LookupGid(groupID)
   800  			if err != nil {
   801  				return "", "", fmt.Errorf("Gid %d has no entry in /etc/passwd: %v", groupID, err)
   802  			}
   803  			groupname = lgrp.Name
   804  		} else {
   805  			// not a number; attempt a lookup
   806  			group, err := user.LookupGroup(idparts[1])
   807  			if err != nil {
   808  				return "", "", fmt.Errorf("Error during gid lookup for %q: %v", idparts[1], err)
   809  			}
   810  			groupID = group.Gid
   811  			groupname = idparts[1]
   812  		}
   813  	}
   814  	return username, groupname, nil
   815  }
   816  
   817  func setupRemappedRoot(config *Config) ([]idtools.IDMap, []idtools.IDMap, error) {
   818  	if runtime.GOOS != "linux" && config.RemappedRoot != "" {
   819  		return nil, nil, fmt.Errorf("User namespaces are only supported on Linux")
   820  	}
   821  
   822  	// if the daemon was started with remapped root option, parse
   823  	// the config option to the int uid,gid values
   824  	var (
   825  		uidMaps, gidMaps []idtools.IDMap
   826  	)
   827  	if config.RemappedRoot != "" {
   828  		username, groupname, err := parseRemappedRoot(config.RemappedRoot)
   829  		if err != nil {
   830  			return nil, nil, err
   831  		}
   832  		if username == "root" {
   833  			// Cannot setup user namespaces with a 1-to-1 mapping; "--root=0:0" is a no-op
   834  			// effectively
   835  			logrus.Warnf("User namespaces: root cannot be remapped with itself; user namespaces are OFF")
   836  			return uidMaps, gidMaps, nil
   837  		}
   838  		logrus.Infof("User namespaces: ID ranges will be mapped to subuid/subgid ranges of: %s:%s", username, groupname)
   839  		// update remapped root setting now that we have resolved them to actual names
   840  		config.RemappedRoot = fmt.Sprintf("%s:%s", username, groupname)
   841  
   842  		uidMaps, gidMaps, err = idtools.CreateIDMappings(username, groupname)
   843  		if err != nil {
   844  			return nil, nil, fmt.Errorf("Can't create ID mappings: %v", err)
   845  		}
   846  	}
   847  	return uidMaps, gidMaps, nil
   848  }
   849  
   850  func setupDaemonRoot(config *Config, rootDir string, rootUID, rootGID int) error {
   851  	config.Root = rootDir
   852  	// the docker root metadata directory needs to have execute permissions for all users (o+x)
   853  	// so that syscalls executing as non-root, operating on subdirectories of the graph root
   854  	// (e.g. mounted layers of a container) can traverse this path.
   855  	// The user namespace support will create subdirectories for the remapped root host uid:gid
   856  	// pair owned by that same uid:gid pair for proper write access to those needed metadata and
   857  	// layer content subtrees.
   858  	if _, err := os.Stat(rootDir); err == nil {
   859  		// root current exists; verify the access bits are correct by setting them
   860  		if err = os.Chmod(rootDir, 0701); err != nil {
   861  			return err
   862  		}
   863  	} else if os.IsNotExist(err) {
   864  		// no root exists yet, create it 0701 with root:root ownership
   865  		if err := os.MkdirAll(rootDir, 0701); err != nil {
   866  			return err
   867  		}
   868  	}
   869  
   870  	// if user namespaces are enabled we will create a subtree underneath the specified root
   871  	// with any/all specified remapped root uid/gid options on the daemon creating
   872  	// a new subdirectory with ownership set to the remapped uid/gid (so as to allow
   873  	// `chdir()` to work for containers namespaced to that uid/gid)
   874  	if config.RemappedRoot != "" {
   875  		config.Root = filepath.Join(rootDir, fmt.Sprintf("%d.%d", rootUID, rootGID))
   876  		logrus.Debugf("Creating user namespaced daemon root: %s", config.Root)
   877  		// Create the root directory if it doesn't exists
   878  		if err := idtools.MkdirAllAs(config.Root, 0700, rootUID, rootGID); err != nil {
   879  			return fmt.Errorf("Cannot create daemon root: %s: %v", config.Root, err)
   880  		}
   881  	}
   882  	return nil
   883  }
   884  
   885  // registerLinks writes the links to a file.
   886  func (daemon *Daemon) registerLinks(container *container.Container, hostConfig *containertypes.HostConfig) error {
   887  	if hostConfig == nil || hostConfig.NetworkMode.IsUserDefined() {
   888  		return nil
   889  	}
   890  
   891  	for _, l := range hostConfig.Links {
   892  		name, alias, err := runconfigopts.ParseLink(l)
   893  		if err != nil {
   894  			return err
   895  		}
   896  		child, err := daemon.GetContainer(name)
   897  		if err != nil {
   898  			//An error from daemon.GetContainer() means this name could not be found
   899  			return fmt.Errorf("Could not get container for %s", name)
   900  		}
   901  		for child.HostConfig.NetworkMode.IsContainer() {
   902  			parts := strings.SplitN(string(child.HostConfig.NetworkMode), ":", 2)
   903  			child, err = daemon.GetContainer(parts[1])
   904  			if err != nil {
   905  				return fmt.Errorf("Could not get container for %s", parts[1])
   906  			}
   907  		}
   908  		if child.HostConfig.NetworkMode.IsHost() {
   909  			return runconfig.ErrConflictHostNetworkAndLinks
   910  		}
   911  		if err := daemon.registerLink(container, child, alias); err != nil {
   912  			return err
   913  		}
   914  	}
   915  
   916  	// After we load all the links into the daemon
   917  	// set them to nil on the hostconfig
   918  	return container.WriteHostConfig()
   919  }
   920  
   921  // conditionalMountOnStart is a platform specific helper function during the
   922  // container start to call mount.
   923  func (daemon *Daemon) conditionalMountOnStart(container *container.Container) error {
   924  	return daemon.Mount(container)
   925  }
   926  
   927  // conditionalUnmountOnCleanup is a platform specific helper function called
   928  // during the cleanup of a container to unmount.
   929  func (daemon *Daemon) conditionalUnmountOnCleanup(container *container.Container) {
   930  	daemon.Unmount(container)
   931  }
   932  
   933  func restoreCustomImage(is image.Store, ls layer.Store, rs reference.Store) error {
   934  	// Unix has no custom images to register
   935  	return nil
   936  }