github.com/ojongerius/docker@v1.11.2/daemon/daemon_unix.go (about)

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