@@ -19,6 +19,7 @@ package cpu
1919import (
2020 "fmt"
2121 "os"
22+ "regexp"
2223 "strconv"
2324 "strings"
2425
@@ -263,9 +264,45 @@ func getCPUModel() map[string]string {
263264 cpuModelInfo ["family" ] = strconv .Itoa (cpuid .CPU .Family )
264265 cpuModelInfo ["id" ] = strconv .Itoa (cpuid .CPU .Model )
265266
267+ hypervisor , err := getHypervisor ()
268+ if err != nil {
269+ klog .ErrorS (err , "failed to detect hypervisor" )
270+ } else if hypervisor != "" {
271+ cpuModelInfo ["hypervisor" ] = hypervisor
272+ }
273+
266274 return cpuModelInfo
267275}
268276
277+ // getHypervisor detects the hypervisor on s390x by reading /proc/sysinfo.
278+ // If the file does not exist, it returns an empty string with no error.
279+ func getHypervisor () (string , error ) {
280+ if _ , err := os .Stat ("/proc/sysinfo" ); os .IsNotExist (err ) {
281+ return "" , nil
282+ }
283+
284+ data , err := os .ReadFile ("/proc/sysinfo" )
285+ if err != nil {
286+ return "" , err
287+ }
288+
289+ hypervisor := "PR/SM"
290+ for _ , line := range strings .Split (string (data ), "\n " ) {
291+ if strings .Contains (line , "Control Program:" ) {
292+ parts := strings .SplitN (line , ":" , 2 )
293+ if len (parts ) == 2 {
294+ hypervisor = strings .TrimSpace (parts [1 ])
295+ }
296+ break
297+ }
298+ }
299+ // Replace forbidden symbols
300+ fullRegex := regexp .MustCompile ("[^-A-Za-z0-9_.]+" )
301+ hypervisor = fullRegex .ReplaceAllString (hypervisor , "_" )
302+
303+ return hypervisor , nil
304+ }
305+
269306func discoverTopology () map [string ]string {
270307 features := make (map [string ]string )
271308
0 commit comments