github.com/docker/engine@v22.0.0-20211208180946-d456264580cf+incompatible/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 9 cdcgroups "github.com/containerd/cgroups" 10 cdseccomp "github.com/containerd/containerd/pkg/seccomp" 11 "github.com/opencontainers/runc/libcontainer/cgroups" 12 "github.com/sirupsen/logrus" 13 ) 14 15 func findCgroupMountpoints() (map[string]string, error) { 16 cgMounts, err := cgroups.GetCgroupMounts(false) 17 if err != nil { 18 return nil, fmt.Errorf("Failed to parse cgroup information: %v", err) 19 } 20 mps := make(map[string]string) 21 for _, m := range cgMounts { 22 for _, ss := range m.Subsystems { 23 mps[ss] = m.Mountpoint 24 } 25 } 26 return mps, nil 27 } 28 29 type infoCollector func(info *SysInfo) 30 31 // WithCgroup2GroupPath specifies the cgroup v2 group path to inspect availability 32 // of the controllers. 33 // 34 // WithCgroup2GroupPath is expected to be used for rootless mode with systemd driver. 35 // 36 // e.g. g = "/user.slice/user-1000.slice/user@1000.service" 37 func WithCgroup2GroupPath(g string) Opt { 38 return func(o *SysInfo) { 39 if p := path.Clean(g); p != "" { 40 o.cg2GroupPath = p 41 } 42 } 43 } 44 45 // New returns a new SysInfo, using the filesystem to detect which features 46 // the kernel supports. 47 func New(options ...Opt) *SysInfo { 48 if cdcgroups.Mode() == cdcgroups.Unified { 49 return newV2(options...) 50 } 51 return newV1() 52 } 53 54 func newV1() *SysInfo { 55 var ( 56 err error 57 sysInfo = &SysInfo{} 58 ) 59 60 ops := []infoCollector{ 61 applyNetworkingInfo, 62 applyAppArmorInfo, 63 applySeccompInfo, 64 applyCgroupNsInfo, 65 } 66 67 sysInfo.cgMounts, err = findCgroupMountpoints() 68 if err != nil { 69 logrus.Warn(err) 70 } else { 71 ops = append(ops, 72 applyMemoryCgroupInfo, 73 applyCPUCgroupInfo, 74 applyBlkioCgroupInfo, 75 applyCPUSetCgroupInfo, 76 applyPIDSCgroupInfo, 77 applyDevicesCgroupInfo, 78 ) 79 } 80 81 for _, o := range ops { 82 o(sysInfo) 83 } 84 return sysInfo 85 } 86 87 // applyMemoryCgroupInfo adds the memory cgroup controller information to the info. 88 func applyMemoryCgroupInfo(info *SysInfo) { 89 mountPoint, ok := info.cgMounts["memory"] 90 if !ok { 91 info.Warnings = append(info.Warnings, "Your kernel does not support cgroup memory limit") 92 return 93 } 94 info.MemoryLimit = ok 95 96 info.SwapLimit = cgroupEnabled(mountPoint, "memory.memsw.limit_in_bytes") 97 if !info.SwapLimit { 98 info.Warnings = append(info.Warnings, "Your kernel does not support swap memory limit") 99 } 100 info.MemoryReservation = cgroupEnabled(mountPoint, "memory.soft_limit_in_bytes") 101 if !info.MemoryReservation { 102 info.Warnings = append(info.Warnings, "Your kernel does not support memory reservation") 103 } 104 info.OomKillDisable = cgroupEnabled(mountPoint, "memory.oom_control") 105 if !info.OomKillDisable { 106 info.Warnings = append(info.Warnings, "Your kernel does not support oom control") 107 } 108 info.MemorySwappiness = cgroupEnabled(mountPoint, "memory.swappiness") 109 if !info.MemorySwappiness { 110 info.Warnings = append(info.Warnings, "Your kernel does not support memory swappiness") 111 } 112 info.KernelMemory = cgroupEnabled(mountPoint, "memory.kmem.limit_in_bytes") 113 if !info.KernelMemory { 114 info.Warnings = append(info.Warnings, "Your kernel does not support kernel memory limit") 115 } 116 info.KernelMemoryTCP = cgroupEnabled(mountPoint, "memory.kmem.tcp.limit_in_bytes") 117 if !info.KernelMemoryTCP { 118 info.Warnings = append(info.Warnings, "Your kernel does not support kernel memory TCP limit") 119 } 120 } 121 122 // applyCPUCgroupInfo adds the cpu cgroup controller information to the info. 123 func applyCPUCgroupInfo(info *SysInfo) { 124 mountPoint, ok := info.cgMounts["cpu"] 125 if !ok { 126 info.Warnings = append(info.Warnings, "Unable to find cpu cgroup in mounts") 127 return 128 } 129 130 info.CPUShares = cgroupEnabled(mountPoint, "cpu.shares") 131 if !info.CPUShares { 132 info.Warnings = append(info.Warnings, "Your kernel does not support CPU shares") 133 } 134 135 info.CPUCfs = cgroupEnabled(mountPoint, "cpu.cfs_quota_us") 136 if !info.CPUCfs { 137 info.Warnings = append(info.Warnings, "Your kernel does not support CPU CFS scheduler") 138 } 139 140 info.CPURealtime = cgroupEnabled(mountPoint, "cpu.rt_period_us") 141 if !info.CPURealtime { 142 info.Warnings = append(info.Warnings, "Your kernel does not support CPU realtime scheduler") 143 } 144 } 145 146 // applyBlkioCgroupInfo adds the blkio cgroup controller information to the info. 147 func applyBlkioCgroupInfo(info *SysInfo) { 148 mountPoint, ok := info.cgMounts["blkio"] 149 if !ok { 150 info.Warnings = append(info.Warnings, "Unable to find blkio cgroup in mounts") 151 return 152 } 153 154 info.BlkioWeight = cgroupEnabled(mountPoint, "blkio.weight") 155 if !info.BlkioWeight { 156 info.Warnings = append(info.Warnings, "Your kernel does not support cgroup blkio weight") 157 } 158 159 info.BlkioWeightDevice = cgroupEnabled(mountPoint, "blkio.weight_device") 160 if !info.BlkioWeightDevice { 161 info.Warnings = append(info.Warnings, "Your kernel does not support cgroup blkio weight_device") 162 } 163 164 info.BlkioReadBpsDevice = cgroupEnabled(mountPoint, "blkio.throttle.read_bps_device") 165 if !info.BlkioReadBpsDevice { 166 info.Warnings = append(info.Warnings, "Your kernel does not support cgroup blkio throttle.read_bps_device") 167 } 168 169 info.BlkioWriteBpsDevice = cgroupEnabled(mountPoint, "blkio.throttle.write_bps_device") 170 if !info.BlkioWriteBpsDevice { 171 info.Warnings = append(info.Warnings, "Your kernel does not support cgroup blkio throttle.write_bps_device") 172 } 173 info.BlkioReadIOpsDevice = cgroupEnabled(mountPoint, "blkio.throttle.read_iops_device") 174 if !info.BlkioReadIOpsDevice { 175 info.Warnings = append(info.Warnings, "Your kernel does not support cgroup blkio throttle.read_iops_device") 176 } 177 178 info.BlkioWriteIOpsDevice = cgroupEnabled(mountPoint, "blkio.throttle.write_iops_device") 179 if !info.BlkioWriteIOpsDevice { 180 info.Warnings = append(info.Warnings, "Your kernel does not support cgroup blkio throttle.write_iops_device") 181 } 182 } 183 184 // applyCPUSetCgroupInfo adds the cpuset cgroup controller information to the info. 185 func applyCPUSetCgroupInfo(info *SysInfo) { 186 mountPoint, ok := info.cgMounts["cpuset"] 187 if !ok { 188 info.Warnings = append(info.Warnings, "Unable to find cpuset cgroup in mounts") 189 return 190 } 191 info.Cpuset = ok 192 193 var err error 194 195 cpus, err := os.ReadFile(path.Join(mountPoint, "cpuset.cpus")) 196 if err != nil { 197 return 198 } 199 info.Cpus = strings.TrimSpace(string(cpus)) 200 201 mems, err := os.ReadFile(path.Join(mountPoint, "cpuset.mems")) 202 if err != nil { 203 return 204 } 205 info.Mems = strings.TrimSpace(string(mems)) 206 } 207 208 // applyPIDSCgroupInfo adds whether the pids cgroup controller is available to the info. 209 func applyPIDSCgroupInfo(info *SysInfo) { 210 _, ok := info.cgMounts["pids"] 211 if !ok { 212 info.Warnings = append(info.Warnings, "Unable to find pids cgroup in mounts") 213 return 214 } 215 info.PidsLimit = true 216 } 217 218 // applyDevicesCgroupInfo adds whether the devices cgroup controller is available to the info. 219 func applyDevicesCgroupInfo(info *SysInfo) { 220 _, ok := info.cgMounts["devices"] 221 info.CgroupDevicesEnabled = ok 222 } 223 224 // applyNetworkingInfo adds networking information to the info. 225 func applyNetworkingInfo(info *SysInfo) { 226 info.IPv4ForwardingDisabled = !readProcBool("/proc/sys/net/ipv4/ip_forward") 227 info.BridgeNFCallIPTablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-iptables") 228 info.BridgeNFCallIP6TablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-ip6tables") 229 } 230 231 // applyAppArmorInfo adds whether AppArmor is enabled to the info. 232 func applyAppArmorInfo(info *SysInfo) { 233 if _, err := os.Stat("/sys/kernel/security/apparmor"); !os.IsNotExist(err) { 234 if _, err := os.ReadFile("/sys/kernel/security/apparmor/profiles"); err == nil { 235 info.AppArmor = true 236 } 237 } 238 } 239 240 // applyCgroupNsInfo adds whether cgroupns is enabled to the info. 241 func applyCgroupNsInfo(info *SysInfo) { 242 if _, err := os.Stat("/proc/self/ns/cgroup"); !os.IsNotExist(err) { 243 info.CgroupNamespaces = true 244 } 245 } 246 247 // applySeccompInfo checks if Seccomp is supported, via CONFIG_SECCOMP. 248 func applySeccompInfo(info *SysInfo) { 249 info.Seccomp = cdseccomp.IsEnabled() 250 } 251 252 func cgroupEnabled(mountPoint, name string) bool { 253 _, err := os.Stat(path.Join(mountPoint, name)) 254 return err == nil 255 } 256 257 func readProcBool(path string) bool { 258 val, err := os.ReadFile(path) 259 if err != nil { 260 return false 261 } 262 return strings.TrimSpace(string(val)) == "1" 263 }