sysinfo_linux.go 7.3 KB

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