github.com/reds/docker@v1.11.2-rc1/pkg/sysinfo/sysinfo_linux.go (about)

     1  package sysinfo
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"path"
     8  	"strings"
     9  	"syscall"
    10  
    11  	"github.com/Sirupsen/logrus"
    12  	"github.com/opencontainers/runc/libcontainer/cgroups"
    13  )
    14  
    15  const (
    16  	// SeccompModeFilter refers to the syscall argument SECCOMP_MODE_FILTER.
    17  	SeccompModeFilter = uintptr(2)
    18  )
    19  
    20  func findCgroupMountpoints() (map[string]string, error) {
    21  	cgMounts, err := cgroups.GetCgroupMounts()
    22  	if err != nil {
    23  		return nil, fmt.Errorf("Failed to parse cgroup information: %v", err)
    24  	}
    25  	mps := make(map[string]string)
    26  	for _, m := range cgMounts {
    27  		for _, ss := range m.Subsystems {
    28  			mps[ss] = m.Mountpoint
    29  		}
    30  	}
    31  	return mps, nil
    32  }
    33  
    34  // New returns a new SysInfo, using the filesystem to detect which features
    35  // the kernel supports. If `quiet` is `false` warnings are printed in logs
    36  // whenever an error occurs or misconfigurations are present.
    37  func New(quiet bool) *SysInfo {
    38  	sysInfo := &SysInfo{}
    39  	cgMounts, err := findCgroupMountpoints()
    40  	if err != nil {
    41  		logrus.Warnf("Failed to parse cgroup information: %v", err)
    42  	} else {
    43  		sysInfo.cgroupMemInfo = checkCgroupMem(cgMounts, quiet)
    44  		sysInfo.cgroupCPUInfo = checkCgroupCPU(cgMounts, quiet)
    45  		sysInfo.cgroupBlkioInfo = checkCgroupBlkioInfo(cgMounts, quiet)
    46  		sysInfo.cgroupCpusetInfo = checkCgroupCpusetInfo(cgMounts, quiet)
    47  		sysInfo.cgroupPids = checkCgroupPids(quiet)
    48  	}
    49  
    50  	_, ok := cgMounts["devices"]
    51  	sysInfo.CgroupDevicesEnabled = ok
    52  
    53  	sysInfo.IPv4ForwardingDisabled = !readProcBool("/proc/sys/net/ipv4/ip_forward")
    54  	sysInfo.BridgeNFCallIPTablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-iptables")
    55  	sysInfo.BridgeNFCallIP6TablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-ip6tables")
    56  
    57  	// Check if AppArmor is supported.
    58  	if _, err := os.Stat("/sys/kernel/security/apparmor"); !os.IsNotExist(err) {
    59  		sysInfo.AppArmor = true
    60  	}
    61  
    62  	// Check if Seccomp is supported, via CONFIG_SECCOMP.
    63  	if _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_GET_SECCOMP, 0, 0); err != syscall.EINVAL {
    64  		// Make sure the kernel has CONFIG_SECCOMP_FILTER.
    65  		if _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_SET_SECCOMP, SeccompModeFilter, 0); err != syscall.EINVAL {
    66  			sysInfo.Seccomp = true
    67  		}
    68  	}
    69  
    70  	return sysInfo
    71  }
    72  
    73  // checkCgroupMem reads the memory information from the memory cgroup mount point.
    74  func checkCgroupMem(cgMounts map[string]string, quiet bool) cgroupMemInfo {
    75  	mountPoint, ok := cgMounts["memory"]
    76  	if !ok {
    77  		if !quiet {
    78  			logrus.Warnf("Your kernel does not support cgroup memory limit")
    79  		}
    80  		return cgroupMemInfo{}
    81  	}
    82  
    83  	swapLimit := cgroupEnabled(mountPoint, "memory.memsw.limit_in_bytes")
    84  	if !quiet && !swapLimit {
    85  		logrus.Warn("Your kernel does not support swap memory limit.")
    86  	}
    87  	memoryReservation := cgroupEnabled(mountPoint, "memory.soft_limit_in_bytes")
    88  	if !quiet && !memoryReservation {
    89  		logrus.Warn("Your kernel does not support memory reservation.")
    90  	}
    91  	oomKillDisable := cgroupEnabled(mountPoint, "memory.oom_control")
    92  	if !quiet && !oomKillDisable {
    93  		logrus.Warnf("Your kernel does not support oom control.")
    94  	}
    95  	memorySwappiness := cgroupEnabled(mountPoint, "memory.swappiness")
    96  	if !quiet && !memorySwappiness {
    97  		logrus.Warnf("Your kernel does not support memory swappiness.")
    98  	}
    99  	kernelMemory := cgroupEnabled(mountPoint, "memory.kmem.limit_in_bytes")
   100  	if !quiet && !kernelMemory {
   101  		logrus.Warnf("Your kernel does not support kernel memory limit.")
   102  	}
   103  
   104  	return cgroupMemInfo{
   105  		MemoryLimit:       true,
   106  		SwapLimit:         swapLimit,
   107  		MemoryReservation: memoryReservation,
   108  		OomKillDisable:    oomKillDisable,
   109  		MemorySwappiness:  memorySwappiness,
   110  		KernelMemory:      kernelMemory,
   111  	}
   112  }
   113  
   114  // checkCgroupCPU reads the cpu information from the cpu cgroup mount point.
   115  func checkCgroupCPU(cgMounts map[string]string, quiet bool) cgroupCPUInfo {
   116  	mountPoint, ok := cgMounts["cpu"]
   117  	if !ok {
   118  		if !quiet {
   119  			logrus.Warnf("Unable to find cpu cgroup in mounts")
   120  		}
   121  		return cgroupCPUInfo{}
   122  	}
   123  
   124  	cpuShares := cgroupEnabled(mountPoint, "cpu.shares")
   125  	if !quiet && !cpuShares {
   126  		logrus.Warn("Your kernel does not support cgroup cpu shares")
   127  	}
   128  
   129  	cpuCfsPeriod := cgroupEnabled(mountPoint, "cpu.cfs_period_us")
   130  	if !quiet && !cpuCfsPeriod {
   131  		logrus.Warn("Your kernel does not support cgroup cfs period")
   132  	}
   133  
   134  	cpuCfsQuota := cgroupEnabled(mountPoint, "cpu.cfs_quota_us")
   135  	if !quiet && !cpuCfsQuota {
   136  		logrus.Warn("Your kernel does not support cgroup cfs quotas")
   137  	}
   138  	return cgroupCPUInfo{
   139  		CPUShares:    cpuShares,
   140  		CPUCfsPeriod: cpuCfsPeriod,
   141  		CPUCfsQuota:  cpuCfsQuota,
   142  	}
   143  }
   144  
   145  // checkCgroupBlkioInfo reads the blkio information from the blkio cgroup mount point.
   146  func checkCgroupBlkioInfo(cgMounts map[string]string, quiet bool) cgroupBlkioInfo {
   147  	mountPoint, ok := cgMounts["blkio"]
   148  	if !ok {
   149  		if !quiet {
   150  			logrus.Warnf("Unable to find blkio cgroup in mounts")
   151  		}
   152  		return cgroupBlkioInfo{}
   153  	}
   154  
   155  	weight := cgroupEnabled(mountPoint, "blkio.weight")
   156  	if !quiet && !weight {
   157  		logrus.Warn("Your kernel does not support cgroup blkio weight")
   158  	}
   159  
   160  	weightDevice := cgroupEnabled(mountPoint, "blkio.weight_device")
   161  	if !quiet && !weightDevice {
   162  		logrus.Warn("Your kernel does not support cgroup blkio weight_device")
   163  	}
   164  
   165  	readBpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.read_bps_device")
   166  	if !quiet && !readBpsDevice {
   167  		logrus.Warn("Your kernel does not support cgroup blkio throttle.read_bps_device")
   168  	}
   169  
   170  	writeBpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.write_bps_device")
   171  	if !quiet && !writeBpsDevice {
   172  		logrus.Warn("Your kernel does not support cgroup blkio throttle.write_bps_device")
   173  	}
   174  	readIOpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.read_iops_device")
   175  	if !quiet && !readIOpsDevice {
   176  		logrus.Warn("Your kernel does not support cgroup blkio throttle.read_iops_device")
   177  	}
   178  
   179  	writeIOpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.write_iops_device")
   180  	if !quiet && !writeIOpsDevice {
   181  		logrus.Warn("Your kernel does not support cgroup blkio throttle.write_iops_device")
   182  	}
   183  	return cgroupBlkioInfo{
   184  		BlkioWeight:          weight,
   185  		BlkioWeightDevice:    weightDevice,
   186  		BlkioReadBpsDevice:   readBpsDevice,
   187  		BlkioWriteBpsDevice:  writeBpsDevice,
   188  		BlkioReadIOpsDevice:  readIOpsDevice,
   189  		BlkioWriteIOpsDevice: writeIOpsDevice,
   190  	}
   191  }
   192  
   193  // checkCgroupCpusetInfo reads the cpuset information from the cpuset cgroup mount point.
   194  func checkCgroupCpusetInfo(cgMounts map[string]string, quiet bool) cgroupCpusetInfo {
   195  	mountPoint, ok := cgMounts["cpuset"]
   196  	if !ok {
   197  		if !quiet {
   198  			logrus.Warnf("Unable to find cpuset cgroup in mounts")
   199  		}
   200  		return cgroupCpusetInfo{}
   201  	}
   202  
   203  	cpus, err := ioutil.ReadFile(path.Join(mountPoint, "cpuset.cpus"))
   204  	if err != nil {
   205  		return cgroupCpusetInfo{}
   206  	}
   207  
   208  	mems, err := ioutil.ReadFile(path.Join(mountPoint, "cpuset.mems"))
   209  	if err != nil {
   210  		return cgroupCpusetInfo{}
   211  	}
   212  
   213  	return cgroupCpusetInfo{
   214  		Cpuset: true,
   215  		Cpus:   strings.TrimSpace(string(cpus)),
   216  		Mems:   strings.TrimSpace(string(mems)),
   217  	}
   218  }
   219  
   220  // checkCgroupPids reads the pids information from the pids cgroup mount point.
   221  func checkCgroupPids(quiet bool) cgroupPids {
   222  	_, err := cgroups.FindCgroupMountpoint("pids")
   223  	if err != nil {
   224  		if !quiet {
   225  			logrus.Warn(err)
   226  		}
   227  		return cgroupPids{}
   228  	}
   229  
   230  	return cgroupPids{
   231  		PidsLimit: true,
   232  	}
   233  }
   234  
   235  func cgroupEnabled(mountPoint, name string) bool {
   236  	_, err := os.Stat(path.Join(mountPoint, name))
   237  	return err == nil
   238  }
   239  
   240  func readProcBool(path string) bool {
   241  	val, err := ioutil.ReadFile(path)
   242  	if err != nil {
   243  		return false
   244  	}
   245  	return strings.TrimSpace(string(val)) == "1"
   246  }