sysinfo_linux.go 7.0 KB

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