github.com/olljanat/moby@v1.13.1/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(false)
    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.Warn("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.Warn("Your kernel does not support oom control")
    94  	}
    95  	memorySwappiness := cgroupEnabled(mountPoint, "memory.swappiness")
    96  	if !quiet && !memorySwappiness {
    97  		logrus.Warn("Your kernel does not support memory swappiness")
    98  	}
    99  	kernelMemory := cgroupEnabled(mountPoint, "memory.kmem.limit_in_bytes")
   100  	if !quiet && !kernelMemory {
   101  		logrus.Warn("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.Warn("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  
   139  	cpuRealtimePeriod := cgroupEnabled(mountPoint, "cpu.rt_period_us")
   140  	if !quiet && !cpuRealtimePeriod {
   141  		logrus.Warn("Your kernel does not support cgroup rt period")
   142  	}
   143  
   144  	cpuRealtimeRuntime := cgroupEnabled(mountPoint, "cpu.rt_runtime_us")
   145  	if !quiet && !cpuRealtimeRuntime {
   146  		logrus.Warn("Your kernel does not support cgroup rt runtime")
   147  	}
   148  
   149  	return cgroupCPUInfo{
   150  		CPUShares:          cpuShares,
   151  		CPUCfsPeriod:       cpuCfsPeriod,
   152  		CPUCfsQuota:        cpuCfsQuota,
   153  		CPURealtimePeriod:  cpuRealtimePeriod,
   154  		CPURealtimeRuntime: cpuRealtimeRuntime,
   155  	}
   156  }
   157  
   158  // checkCgroupBlkioInfo reads the blkio information from the blkio cgroup mount point.
   159  func checkCgroupBlkioInfo(cgMounts map[string]string, quiet bool) cgroupBlkioInfo {
   160  	mountPoint, ok := cgMounts["blkio"]
   161  	if !ok {
   162  		if !quiet {
   163  			logrus.Warn("Unable to find blkio cgroup in mounts")
   164  		}
   165  		return cgroupBlkioInfo{}
   166  	}
   167  
   168  	weight := cgroupEnabled(mountPoint, "blkio.weight")
   169  	if !quiet && !weight {
   170  		logrus.Warn("Your kernel does not support cgroup blkio weight")
   171  	}
   172  
   173  	weightDevice := cgroupEnabled(mountPoint, "blkio.weight_device")
   174  	if !quiet && !weightDevice {
   175  		logrus.Warn("Your kernel does not support cgroup blkio weight_device")
   176  	}
   177  
   178  	readBpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.read_bps_device")
   179  	if !quiet && !readBpsDevice {
   180  		logrus.Warn("Your kernel does not support cgroup blkio throttle.read_bps_device")
   181  	}
   182  
   183  	writeBpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.write_bps_device")
   184  	if !quiet && !writeBpsDevice {
   185  		logrus.Warn("Your kernel does not support cgroup blkio throttle.write_bps_device")
   186  	}
   187  	readIOpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.read_iops_device")
   188  	if !quiet && !readIOpsDevice {
   189  		logrus.Warn("Your kernel does not support cgroup blkio throttle.read_iops_device")
   190  	}
   191  
   192  	writeIOpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.write_iops_device")
   193  	if !quiet && !writeIOpsDevice {
   194  		logrus.Warn("Your kernel does not support cgroup blkio throttle.write_iops_device")
   195  	}
   196  	return cgroupBlkioInfo{
   197  		BlkioWeight:          weight,
   198  		BlkioWeightDevice:    weightDevice,
   199  		BlkioReadBpsDevice:   readBpsDevice,
   200  		BlkioWriteBpsDevice:  writeBpsDevice,
   201  		BlkioReadIOpsDevice:  readIOpsDevice,
   202  		BlkioWriteIOpsDevice: writeIOpsDevice,
   203  	}
   204  }
   205  
   206  // checkCgroupCpusetInfo reads the cpuset information from the cpuset cgroup mount point.
   207  func checkCgroupCpusetInfo(cgMounts map[string]string, quiet bool) cgroupCpusetInfo {
   208  	mountPoint, ok := cgMounts["cpuset"]
   209  	if !ok {
   210  		if !quiet {
   211  			logrus.Warn("Unable to find cpuset cgroup in mounts")
   212  		}
   213  		return cgroupCpusetInfo{}
   214  	}
   215  
   216  	cpus, err := ioutil.ReadFile(path.Join(mountPoint, "cpuset.cpus"))
   217  	if err != nil {
   218  		return cgroupCpusetInfo{}
   219  	}
   220  
   221  	mems, err := ioutil.ReadFile(path.Join(mountPoint, "cpuset.mems"))
   222  	if err != nil {
   223  		return cgroupCpusetInfo{}
   224  	}
   225  
   226  	return cgroupCpusetInfo{
   227  		Cpuset: true,
   228  		Cpus:   strings.TrimSpace(string(cpus)),
   229  		Mems:   strings.TrimSpace(string(mems)),
   230  	}
   231  }
   232  
   233  // checkCgroupPids reads the pids information from the pids cgroup mount point.
   234  func checkCgroupPids(quiet bool) cgroupPids {
   235  	_, err := cgroups.FindCgroupMountpoint("pids")
   236  	if err != nil {
   237  		if !quiet {
   238  			logrus.Warn(err)
   239  		}
   240  		return cgroupPids{}
   241  	}
   242  
   243  	return cgroupPids{
   244  		PidsLimit: true,
   245  	}
   246  }
   247  
   248  func cgroupEnabled(mountPoint, name string) bool {
   249  	_, err := os.Stat(path.Join(mountPoint, name))
   250  	return err == nil
   251  }
   252  
   253  func readProcBool(path string) bool {
   254  	val, err := ioutil.ReadFile(path)
   255  	if err != nil {
   256  		return false
   257  	}
   258  	return strings.TrimSpace(string(val)) == "1"
   259  }