sysinfo_linux.go 8.0 KB

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