github.com/ncdc/docker@v0.10.1-0.20160129113957-6c6729ef5b74/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  	}
    48  
    49  	_, ok := cgMounts["devices"]
    50  	sysInfo.CgroupDevicesEnabled = ok
    51  
    52  	sysInfo.IPv4ForwardingDisabled = !readProcBool("/proc/sys/net/ipv4/ip_forward")
    53  	sysInfo.BridgeNfCallIptablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-iptables")
    54  	sysInfo.BridgeNfCallIP6tablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-ip6tables")
    55  
    56  	// Check if AppArmor is supported.
    57  	if _, err := os.Stat("/sys/kernel/security/apparmor"); !os.IsNotExist(err) {
    58  		sysInfo.AppArmor = true
    59  	}
    60  
    61  	// Check if Seccomp is supported, via CONFIG_SECCOMP.
    62  	if _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_GET_SECCOMP, 0, 0); err != syscall.EINVAL {
    63  		// Make sure the kernel has CONFIG_SECCOMP_FILTER.
    64  		if _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_SET_SECCOMP, SeccompModeFilter, 0); err != syscall.EINVAL {
    65  			sysInfo.Seccomp = true
    66  		}
    67  	}
    68  
    69  	return sysInfo
    70  }
    71  
    72  // checkCgroupMem reads the memory information from the memory cgroup mount point.
    73  func checkCgroupMem(cgMounts map[string]string, quiet bool) cgroupMemInfo {
    74  	mountPoint, ok := cgMounts["memory"]
    75  	if !ok {
    76  		if !quiet {
    77  			logrus.Warnf("Your kernel does not support cgroup memory limit")
    78  		}
    79  		return cgroupMemInfo{}
    80  	}
    81  
    82  	swapLimit := cgroupEnabled(mountPoint, "memory.memsw.limit_in_bytes")
    83  	if !quiet && !swapLimit {
    84  		logrus.Warn("Your kernel does not support swap memory limit.")
    85  	}
    86  	memoryReservation := cgroupEnabled(mountPoint, "memory.soft_limit_in_bytes")
    87  	if !quiet && !memoryReservation {
    88  		logrus.Warn("Your kernel does not support memory reservation.")
    89  	}
    90  	oomKillDisable := cgroupEnabled(mountPoint, "memory.oom_control")
    91  	if !quiet && !oomKillDisable {
    92  		logrus.Warnf("Your kernel does not support oom control.")
    93  	}
    94  	memorySwappiness := cgroupEnabled(mountPoint, "memory.swappiness")
    95  	if !quiet && !memorySwappiness {
    96  		logrus.Warnf("Your kernel does not support memory swappiness.")
    97  	}
    98  	kernelMemory := cgroupEnabled(mountPoint, "memory.kmem.limit_in_bytes")
    99  	if !quiet && !kernelMemory {
   100  		logrus.Warnf("Your kernel does not support kernel memory limit.")
   101  	}
   102  
   103  	return cgroupMemInfo{
   104  		MemoryLimit:       true,
   105  		SwapLimit:         swapLimit,
   106  		MemoryReservation: memoryReservation,
   107  		OomKillDisable:    oomKillDisable,
   108  		MemorySwappiness:  memorySwappiness,
   109  		KernelMemory:      kernelMemory,
   110  	}
   111  }
   112  
   113  // checkCgroupCPU reads the cpu information from the cpu cgroup mount point.
   114  func checkCgroupCPU(cgMounts map[string]string, quiet bool) cgroupCPUInfo {
   115  	mountPoint, ok := cgMounts["cpu"]
   116  	if !ok {
   117  		if !quiet {
   118  			logrus.Warnf("Unable to find cpu cgroup in mounts")
   119  		}
   120  		return cgroupCPUInfo{}
   121  	}
   122  
   123  	cpuShares := cgroupEnabled(mountPoint, "cpu.shares")
   124  	if !quiet && !cpuShares {
   125  		logrus.Warn("Your kernel does not support cgroup cpu shares")
   126  	}
   127  
   128  	cpuCfsPeriod := cgroupEnabled(mountPoint, "cpu.cfs_period_us")
   129  	if !quiet && !cpuCfsPeriod {
   130  		logrus.Warn("Your kernel does not support cgroup cfs period")
   131  	}
   132  
   133  	cpuCfsQuota := cgroupEnabled(mountPoint, "cpu.cfs_quota_us")
   134  	if !quiet && !cpuCfsQuota {
   135  		logrus.Warn("Your kernel does not support cgroup cfs quotas")
   136  	}
   137  	return cgroupCPUInfo{
   138  		CPUShares:    cpuShares,
   139  		CPUCfsPeriod: cpuCfsPeriod,
   140  		CPUCfsQuota:  cpuCfsQuota,
   141  	}
   142  }
   143  
   144  // checkCgroupBlkioInfo reads the blkio information from the blkio cgroup mount point.
   145  func checkCgroupBlkioInfo(cgMounts map[string]string, quiet bool) cgroupBlkioInfo {
   146  	mountPoint, ok := cgMounts["blkio"]
   147  	if !ok {
   148  		if !quiet {
   149  			logrus.Warnf("Unable to find blkio cgroup in mounts")
   150  		}
   151  		return cgroupBlkioInfo{}
   152  	}
   153  
   154  	weight := cgroupEnabled(mountPoint, "blkio.weight")
   155  	if !quiet && !weight {
   156  		logrus.Warn("Your kernel does not support cgroup blkio weight")
   157  	}
   158  
   159  	weightDevice := cgroupEnabled(mountPoint, "blkio.weight_device")
   160  	if !quiet && !weightDevice {
   161  		logrus.Warn("Your kernel does not support cgroup blkio weight_device")
   162  	}
   163  
   164  	readBpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.read_bps_device")
   165  	if !quiet && !readBpsDevice {
   166  		logrus.Warn("Your kernel does not support cgroup blkio throttle.read_bps_device")
   167  	}
   168  
   169  	writeBpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.write_bps_device")
   170  	if !quiet && !writeBpsDevice {
   171  		logrus.Warn("Your kernel does not support cgroup blkio throttle.write_bps_device")
   172  	}
   173  	readIOpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.read_iops_device")
   174  	if !quiet && !readIOpsDevice {
   175  		logrus.Warn("Your kernel does not support cgroup blkio throttle.read_iops_device")
   176  	}
   177  
   178  	writeIOpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.write_iops_device")
   179  	if !quiet && !writeIOpsDevice {
   180  		logrus.Warn("Your kernel does not support cgroup blkio throttle.write_iops_device")
   181  	}
   182  	return cgroupBlkioInfo{
   183  		BlkioWeight:          weight,
   184  		BlkioWeightDevice:    weightDevice,
   185  		BlkioReadBpsDevice:   readBpsDevice,
   186  		BlkioWriteBpsDevice:  writeBpsDevice,
   187  		BlkioReadIOpsDevice:  readIOpsDevice,
   188  		BlkioWriteIOpsDevice: writeIOpsDevice,
   189  	}
   190  }
   191  
   192  // checkCgroupCpusetInfo reads the cpuset information from the cpuset cgroup mount point.
   193  func checkCgroupCpusetInfo(cgMounts map[string]string, quiet bool) cgroupCpusetInfo {
   194  	mountPoint, ok := cgMounts["cpuset"]
   195  	if !ok {
   196  		if !quiet {
   197  			logrus.Warnf("Unable to find cpuset cgroup in mounts")
   198  		}
   199  		return cgroupCpusetInfo{}
   200  	}
   201  
   202  	cpus, err := ioutil.ReadFile(path.Join(mountPoint, "cpuset.cpus"))
   203  	if err != nil {
   204  		return cgroupCpusetInfo{}
   205  	}
   206  
   207  	mems, err := ioutil.ReadFile(path.Join(mountPoint, "cpuset.mems"))
   208  	if err != nil {
   209  		return cgroupCpusetInfo{}
   210  	}
   211  
   212  	return cgroupCpusetInfo{
   213  		Cpuset: true,
   214  		Cpus:   strings.TrimSpace(string(cpus)),
   215  		Mems:   strings.TrimSpace(string(mems)),
   216  	}
   217  }
   218  
   219  func cgroupEnabled(mountPoint, name string) bool {
   220  	_, err := os.Stat(path.Join(mountPoint, name))
   221  	return err == nil
   222  }
   223  
   224  func readProcBool(path string) bool {
   225  	val, err := ioutil.ReadFile(path)
   226  	if err != nil {
   227  		return false
   228  	}
   229  	return strings.TrimSpace(string(val)) == "1"
   230  }