github.com/vincentwoo/docker@v0.7.3-0.20160116130405-82401a4b13c0/pkg/sysinfo/sysinfo_linux.go (about)

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