sysinfo_linux.go 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  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. sysInfo.AppArmor = true
  48. }
  49. // Check if Seccomp is supported, via CONFIG_SECCOMP.
  50. if err := unix.Prctl(unix.PR_GET_SECCOMP, 0, 0, 0, 0); err != unix.EINVAL {
  51. // Make sure the kernel has CONFIG_SECCOMP_FILTER.
  52. if err := unix.Prctl(unix.PR_SET_SECCOMP, unix.SECCOMP_MODE_FILTER, 0, 0, 0); err != unix.EINVAL {
  53. sysInfo.Seccomp = true
  54. }
  55. }
  56. return sysInfo
  57. }
  58. // checkCgroupMem reads the memory information from the memory cgroup mount point.
  59. func checkCgroupMem(cgMounts map[string]string, quiet bool) cgroupMemInfo {
  60. mountPoint, ok := cgMounts["memory"]
  61. if !ok {
  62. if !quiet {
  63. logrus.Warn("Your kernel does not support cgroup memory limit")
  64. }
  65. return cgroupMemInfo{}
  66. }
  67. swapLimit := cgroupEnabled(mountPoint, "memory.memsw.limit_in_bytes")
  68. if !quiet && !swapLimit {
  69. logrus.Warn("Your kernel does not support swap memory limit")
  70. }
  71. memoryReservation := cgroupEnabled(mountPoint, "memory.soft_limit_in_bytes")
  72. if !quiet && !memoryReservation {
  73. logrus.Warn("Your kernel does not support memory reservation")
  74. }
  75. oomKillDisable := cgroupEnabled(mountPoint, "memory.oom_control")
  76. if !quiet && !oomKillDisable {
  77. logrus.Warn("Your kernel does not support oom control")
  78. }
  79. memorySwappiness := cgroupEnabled(mountPoint, "memory.swappiness")
  80. if !quiet && !memorySwappiness {
  81. logrus.Warn("Your kernel does not support memory swappiness")
  82. }
  83. kernelMemory := cgroupEnabled(mountPoint, "memory.kmem.limit_in_bytes")
  84. if !quiet && !kernelMemory {
  85. logrus.Warn("Your kernel does not support kernel memory limit")
  86. }
  87. return cgroupMemInfo{
  88. MemoryLimit: true,
  89. SwapLimit: swapLimit,
  90. MemoryReservation: memoryReservation,
  91. OomKillDisable: oomKillDisable,
  92. MemorySwappiness: memorySwappiness,
  93. KernelMemory: kernelMemory,
  94. }
  95. }
  96. // checkCgroupCPU reads the cpu information from the cpu cgroup mount point.
  97. func checkCgroupCPU(cgMounts map[string]string, quiet bool) cgroupCPUInfo {
  98. mountPoint, ok := cgMounts["cpu"]
  99. if !ok {
  100. if !quiet {
  101. logrus.Warn("Unable to find cpu cgroup in mounts")
  102. }
  103. return cgroupCPUInfo{}
  104. }
  105. cpuShares := cgroupEnabled(mountPoint, "cpu.shares")
  106. if !quiet && !cpuShares {
  107. logrus.Warn("Your kernel does not support cgroup cpu shares")
  108. }
  109. cpuCfsPeriod := cgroupEnabled(mountPoint, "cpu.cfs_period_us")
  110. if !quiet && !cpuCfsPeriod {
  111. logrus.Warn("Your kernel does not support cgroup cfs period")
  112. }
  113. cpuCfsQuota := cgroupEnabled(mountPoint, "cpu.cfs_quota_us")
  114. if !quiet && !cpuCfsQuota {
  115. logrus.Warn("Your kernel does not support cgroup cfs quotas")
  116. }
  117. cpuRealtimePeriod := cgroupEnabled(mountPoint, "cpu.rt_period_us")
  118. if !quiet && !cpuRealtimePeriod {
  119. logrus.Warn("Your kernel does not support cgroup rt period")
  120. }
  121. cpuRealtimeRuntime := cgroupEnabled(mountPoint, "cpu.rt_runtime_us")
  122. if !quiet && !cpuRealtimeRuntime {
  123. logrus.Warn("Your kernel does not support cgroup rt runtime")
  124. }
  125. return cgroupCPUInfo{
  126. CPUShares: cpuShares,
  127. CPUCfsPeriod: cpuCfsPeriod,
  128. CPUCfsQuota: cpuCfsQuota,
  129. CPURealtimePeriod: cpuRealtimePeriod,
  130. CPURealtimeRuntime: cpuRealtimeRuntime,
  131. }
  132. }
  133. // checkCgroupBlkioInfo reads the blkio information from the blkio cgroup mount point.
  134. func checkCgroupBlkioInfo(cgMounts map[string]string, quiet bool) cgroupBlkioInfo {
  135. mountPoint, ok := cgMounts["blkio"]
  136. if !ok {
  137. if !quiet {
  138. logrus.Warn("Unable to find blkio cgroup in mounts")
  139. }
  140. return cgroupBlkioInfo{}
  141. }
  142. weight := cgroupEnabled(mountPoint, "blkio.weight")
  143. if !quiet && !weight {
  144. logrus.Warn("Your kernel does not support cgroup blkio weight")
  145. }
  146. weightDevice := cgroupEnabled(mountPoint, "blkio.weight_device")
  147. if !quiet && !weightDevice {
  148. logrus.Warn("Your kernel does not support cgroup blkio weight_device")
  149. }
  150. readBpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.read_bps_device")
  151. if !quiet && !readBpsDevice {
  152. logrus.Warn("Your kernel does not support cgroup blkio throttle.read_bps_device")
  153. }
  154. writeBpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.write_bps_device")
  155. if !quiet && !writeBpsDevice {
  156. logrus.Warn("Your kernel does not support cgroup blkio throttle.write_bps_device")
  157. }
  158. readIOpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.read_iops_device")
  159. if !quiet && !readIOpsDevice {
  160. logrus.Warn("Your kernel does not support cgroup blkio throttle.read_iops_device")
  161. }
  162. writeIOpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.write_iops_device")
  163. if !quiet && !writeIOpsDevice {
  164. logrus.Warn("Your kernel does not support cgroup blkio throttle.write_iops_device")
  165. }
  166. return cgroupBlkioInfo{
  167. BlkioWeight: weight,
  168. BlkioWeightDevice: weightDevice,
  169. BlkioReadBpsDevice: readBpsDevice,
  170. BlkioWriteBpsDevice: writeBpsDevice,
  171. BlkioReadIOpsDevice: readIOpsDevice,
  172. BlkioWriteIOpsDevice: writeIOpsDevice,
  173. }
  174. }
  175. // checkCgroupCpusetInfo reads the cpuset information from the cpuset cgroup mount point.
  176. func checkCgroupCpusetInfo(cgMounts map[string]string, quiet bool) cgroupCpusetInfo {
  177. mountPoint, ok := cgMounts["cpuset"]
  178. if !ok {
  179. if !quiet {
  180. logrus.Warn("Unable to find cpuset cgroup in mounts")
  181. }
  182. return cgroupCpusetInfo{}
  183. }
  184. cpus, err := ioutil.ReadFile(path.Join(mountPoint, "cpuset.cpus"))
  185. if err != nil {
  186. return cgroupCpusetInfo{}
  187. }
  188. mems, err := ioutil.ReadFile(path.Join(mountPoint, "cpuset.mems"))
  189. if err != nil {
  190. return cgroupCpusetInfo{}
  191. }
  192. return cgroupCpusetInfo{
  193. Cpuset: true,
  194. Cpus: strings.TrimSpace(string(cpus)),
  195. Mems: strings.TrimSpace(string(mems)),
  196. }
  197. }
  198. // checkCgroupPids reads the pids information from the pids cgroup mount point.
  199. func checkCgroupPids(quiet bool) cgroupPids {
  200. _, err := cgroups.FindCgroupMountpoint("", "pids")
  201. if err != nil {
  202. if !quiet {
  203. logrus.Warn(err)
  204. }
  205. return cgroupPids{}
  206. }
  207. return cgroupPids{
  208. PidsLimit: true,
  209. }
  210. }
  211. func cgroupEnabled(mountPoint, name string) bool {
  212. _, err := os.Stat(path.Join(mountPoint, name))
  213. return err == nil
  214. }
  215. func readProcBool(path string) bool {
  216. val, err := ioutil.ReadFile(path)
  217. if err != nil {
  218. return false
  219. }
  220. return strings.TrimSpace(string(val)) == "1"
  221. }