github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/engine/pkg/sysinfo/sysinfo_linux.go (about) 1 package sysinfo // import "github.com/docker/docker/pkg/sysinfo" 2 3 import ( 4 "fmt" 5 "os" 6 "path" 7 "strings" 8 "sync" 9 10 cdcgroups "github.com/containerd/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 type infoCollector func(info *SysInfo, cgMounts map[string]string) (warnings []string) 31 32 type opts struct { 33 cg2GroupPath string 34 } 35 36 // Opt for New(). 37 type Opt func(*opts) 38 39 // WithCgroup2GroupPath specifies the cgroup v2 group path to inspect availability 40 // of the controllers. 41 // 42 // WithCgroup2GroupPath is expected to be used for rootless mode with systemd driver. 43 // 44 // e.g. g = "/user.slice/user-1000.slice/user@1000.service" 45 func WithCgroup2GroupPath(g string) Opt { 46 return func(o *opts) { 47 o.cg2GroupPath = path.Clean(g) 48 } 49 } 50 51 // New returns a new SysInfo, using the filesystem to detect which features 52 // the kernel supports. If `quiet` is `false` warnings are printed in logs 53 // whenever an error occurs or misconfigurations are present. 54 func New(quiet bool, options ...Opt) *SysInfo { 55 var opts opts 56 for _, o := range options { 57 o(&opts) 58 } 59 if cdcgroups.Mode() == cdcgroups.Unified { 60 return newV2(quiet, &opts) 61 } 62 63 var ops []infoCollector 64 var warnings []string 65 sysInfo := &SysInfo{} 66 cgMounts, err := findCgroupMountpoints() 67 if err != nil { 68 logrus.Warn(err) 69 } else { 70 ops = append(ops, []infoCollector{ 71 applyMemoryCgroupInfo, 72 applyCPUCgroupInfo, 73 applyBlkioCgroupInfo, 74 applyCPUSetCgroupInfo, 75 applyPIDSCgroupInfo, 76 applyDevicesCgroupInfo, 77 }...) 78 } 79 80 ops = append(ops, []infoCollector{ 81 applyNetworkingInfo, 82 applyAppArmorInfo, 83 applySeccompInfo, 84 applyCgroupNsInfo, 85 }...) 86 87 for _, o := range ops { 88 w := o(sysInfo, cgMounts) 89 warnings = append(warnings, w...) 90 } 91 if !quiet { 92 for _, w := range warnings { 93 logrus.Warn(w) 94 } 95 } 96 return sysInfo 97 } 98 99 // applyMemoryCgroupInfo adds the memory cgroup controller information to the info. 100 func applyMemoryCgroupInfo(info *SysInfo, cgMounts map[string]string) []string { 101 var warnings []string 102 mountPoint, ok := cgMounts["memory"] 103 if !ok { 104 warnings = append(warnings, "Your kernel does not support cgroup memory limit") 105 return warnings 106 } 107 info.MemoryLimit = ok 108 109 info.SwapLimit = cgroupEnabled(mountPoint, "memory.memsw.limit_in_bytes") 110 if !info.SwapLimit { 111 warnings = append(warnings, "Your kernel does not support swap memory limit") 112 } 113 info.MemoryReservation = cgroupEnabled(mountPoint, "memory.soft_limit_in_bytes") 114 if !info.MemoryReservation { 115 warnings = append(warnings, "Your kernel does not support memory reservation") 116 } 117 info.OomKillDisable = cgroupEnabled(mountPoint, "memory.oom_control") 118 if !info.OomKillDisable { 119 warnings = append(warnings, "Your kernel does not support oom control") 120 } 121 info.MemorySwappiness = cgroupEnabled(mountPoint, "memory.swappiness") 122 if !info.MemorySwappiness { 123 warnings = append(warnings, "Your kernel does not support memory swappiness") 124 } 125 info.KernelMemory = cgroupEnabled(mountPoint, "memory.kmem.limit_in_bytes") 126 if !info.KernelMemory { 127 warnings = append(warnings, "Your kernel does not support kernel memory limit") 128 } 129 info.KernelMemoryTCP = cgroupEnabled(mountPoint, "memory.kmem.tcp.limit_in_bytes") 130 if !info.KernelMemoryTCP { 131 warnings = append(warnings, "Your kernel does not support kernel memory TCP limit") 132 } 133 134 return warnings 135 } 136 137 // applyCPUCgroupInfo adds the cpu cgroup controller information to the info. 138 func applyCPUCgroupInfo(info *SysInfo, cgMounts map[string]string) []string { 139 var warnings []string 140 mountPoint, ok := cgMounts["cpu"] 141 if !ok { 142 warnings = append(warnings, "Unable to find cpu cgroup in mounts") 143 return warnings 144 } 145 146 info.CPUShares = cgroupEnabled(mountPoint, "cpu.shares") 147 if !info.CPUShares { 148 warnings = append(warnings, "Your kernel does not support CPU shares") 149 } 150 151 info.CPUCfs = cgroupEnabled(mountPoint, "cpu.cfs_quota_us") 152 if !info.CPUCfs { 153 warnings = append(warnings, "Your kernel does not support CPU CFS scheduler") 154 } 155 156 info.CPURealtime = cgroupEnabled(mountPoint, "cpu.rt_period_us") 157 if !info.CPURealtime { 158 warnings = append(warnings, "Your kernel does not support CPU realtime scheduler") 159 } 160 161 return warnings 162 } 163 164 // applyBlkioCgroupInfo adds the blkio cgroup controller information to the info. 165 func applyBlkioCgroupInfo(info *SysInfo, cgMounts map[string]string) []string { 166 var warnings []string 167 mountPoint, ok := cgMounts["blkio"] 168 if !ok { 169 warnings = append(warnings, "Unable to find blkio cgroup in mounts") 170 return warnings 171 } 172 173 info.BlkioWeight = cgroupEnabled(mountPoint, "blkio.weight") 174 if !info.BlkioWeight { 175 warnings = append(warnings, "Your kernel does not support cgroup blkio weight") 176 } 177 178 info.BlkioWeightDevice = cgroupEnabled(mountPoint, "blkio.weight_device") 179 if !info.BlkioWeightDevice { 180 warnings = append(warnings, "Your kernel does not support cgroup blkio weight_device") 181 } 182 183 info.BlkioReadBpsDevice = cgroupEnabled(mountPoint, "blkio.throttle.read_bps_device") 184 if !info.BlkioReadBpsDevice { 185 warnings = append(warnings, "Your kernel does not support cgroup blkio throttle.read_bps_device") 186 } 187 188 info.BlkioWriteBpsDevice = cgroupEnabled(mountPoint, "blkio.throttle.write_bps_device") 189 if !info.BlkioWriteBpsDevice { 190 warnings = append(warnings, "Your kernel does not support cgroup blkio throttle.write_bps_device") 191 } 192 info.BlkioReadIOpsDevice = cgroupEnabled(mountPoint, "blkio.throttle.read_iops_device") 193 if !info.BlkioReadIOpsDevice { 194 warnings = append(warnings, "Your kernel does not support cgroup blkio throttle.read_iops_device") 195 } 196 197 info.BlkioWriteIOpsDevice = cgroupEnabled(mountPoint, "blkio.throttle.write_iops_device") 198 if !info.BlkioWriteIOpsDevice { 199 warnings = append(warnings, "Your kernel does not support cgroup blkio throttle.write_iops_device") 200 } 201 202 return warnings 203 } 204 205 // applyCPUSetCgroupInfo adds the cpuset cgroup controller information to the info. 206 func applyCPUSetCgroupInfo(info *SysInfo, cgMounts map[string]string) []string { 207 var warnings []string 208 mountPoint, ok := cgMounts["cpuset"] 209 if !ok { 210 warnings = append(warnings, "Unable to find cpuset cgroup in mounts") 211 return warnings 212 } 213 info.Cpuset = ok 214 215 var err error 216 217 cpus, err := os.ReadFile(path.Join(mountPoint, "cpuset.cpus")) 218 if err != nil { 219 return warnings 220 } 221 info.Cpus = strings.TrimSpace(string(cpus)) 222 223 mems, err := os.ReadFile(path.Join(mountPoint, "cpuset.mems")) 224 if err != nil { 225 return warnings 226 } 227 info.Mems = strings.TrimSpace(string(mems)) 228 229 return warnings 230 } 231 232 // applyPIDSCgroupInfo adds whether the pids cgroup controller is available to the info. 233 func applyPIDSCgroupInfo(info *SysInfo, cgMounts map[string]string) []string { 234 var warnings []string 235 _, ok := cgMounts["pids"] 236 if !ok { 237 warnings = append(warnings, "Unable to find pids cgroup in mounts") 238 return warnings 239 } 240 info.PidsLimit = true 241 return warnings 242 } 243 244 // applyDevicesCgroupInfo adds whether the devices cgroup controller is available to the info. 245 func applyDevicesCgroupInfo(info *SysInfo, cgMounts map[string]string) []string { 246 var warnings []string 247 _, ok := cgMounts["devices"] 248 info.CgroupDevicesEnabled = ok 249 return warnings 250 } 251 252 // applyNetworkingInfo adds networking information to the info. 253 func applyNetworkingInfo(info *SysInfo, _ map[string]string) []string { 254 var warnings []string 255 info.IPv4ForwardingDisabled = !readProcBool("/proc/sys/net/ipv4/ip_forward") 256 info.BridgeNFCallIPTablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-iptables") 257 info.BridgeNFCallIP6TablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-ip6tables") 258 return warnings 259 } 260 261 // applyAppArmorInfo adds whether AppArmor is enabled to the info. 262 func applyAppArmorInfo(info *SysInfo, _ map[string]string) []string { 263 var warnings []string 264 if _, err := os.Stat("/sys/kernel/security/apparmor"); !os.IsNotExist(err) { 265 if _, err := os.ReadFile("/sys/kernel/security/apparmor/profiles"); err == nil { 266 info.AppArmor = true 267 } 268 } 269 return warnings 270 } 271 272 // applyCgroupNsInfo adds whether cgroupns is enabled to the info. 273 func applyCgroupNsInfo(info *SysInfo, _ map[string]string) []string { 274 var warnings []string 275 if _, err := os.Stat("/proc/self/ns/cgroup"); !os.IsNotExist(err) { 276 info.CgroupNamespaces = true 277 } 278 return warnings 279 } 280 281 var ( 282 seccompOnce sync.Once 283 seccompEnabled bool 284 ) 285 286 // applySeccompInfo checks if Seccomp is supported, via CONFIG_SECCOMP. 287 func applySeccompInfo(info *SysInfo, _ map[string]string) []string { 288 var warnings []string 289 seccompOnce.Do(func() { 290 // Check if Seccomp is supported, via CONFIG_SECCOMP. 291 if err := unix.Prctl(unix.PR_GET_SECCOMP, 0, 0, 0, 0); err != unix.EINVAL { 292 // Make sure the kernel has CONFIG_SECCOMP_FILTER. 293 if err := unix.Prctl(unix.PR_SET_SECCOMP, unix.SECCOMP_MODE_FILTER, 0, 0, 0); err != unix.EINVAL { 294 seccompEnabled = true 295 } 296 } 297 }) 298 info.Seccomp = seccompEnabled 299 return warnings 300 } 301 302 func cgroupEnabled(mountPoint, name string) bool { 303 _, err := os.Stat(path.Join(mountPoint, name)) 304 return err == nil 305 } 306 307 func readProcBool(path string) bool { 308 val, err := os.ReadFile(path) 309 if err != nil { 310 return false 311 } 312 return strings.TrimSpace(string(val)) == "1" 313 }