github.com/gdevillele/moby@v1.13.0/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 }