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