diff --git a/pkg/hostman/guestman/qemu-kvm.go b/pkg/hostman/guestman/qemu-kvm.go index 7bd21d6c69..1898d92565 100644 --- a/pkg/hostman/guestman/qemu-kvm.go +++ b/pkg/hostman/guestman/qemu-kvm.go @@ -2655,7 +2655,7 @@ func (s *SKVMGuestInstance) generateDiskSetupScripts(disks []*desc.SGuestDisk) ( return cmd, nil } -func (s *SKVMGuestInstance) getSriovDeviceByNetworkIndex(networkIndex int8) (isolated_device.IDevice, error) { +func (s *SKVMGuestInstance) GetSriovDeviceByNetworkIndex(networkIndex int8) (isolated_device.IDevice, error) { manager := s.manager.GetHost().GetIsolatedDeviceManager() for i := 0; i < len(s.Desc.IsolatedDevices); i++ { if s.Desc.IsolatedDevices[i].DevType == api.NIC_TYPE && @@ -2710,7 +2710,7 @@ func (s *SKVMGuestInstance) generateSRIOVInitScripts() (string, error) { for i := range s.Desc.Nics { if s.Desc.Nics[i].Driver == "vfio-pci" { - dev, err := s.getSriovDeviceByNetworkIndex(s.Desc.Nics[i].Index) + dev, err := s.GetSriovDeviceByNetworkIndex(s.Desc.Nics[i].Index) if err != nil { return "", err } diff --git a/pkg/hostman/hostmetrics/hostmetrics.go b/pkg/hostman/hostmetrics/hostmetrics.go index 3d29ac28a9..aae4ae2c00 100644 --- a/pkg/hostman/hostmetrics/hostmetrics.go +++ b/pkg/hostman/hostmetrics/hostmetrics.go @@ -17,6 +17,7 @@ package hostmetrics import ( "context" "fmt" + "math" "reflect" "runtime/debug" "strconv" @@ -30,6 +31,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/httputils" "yunion.io/x/pkg/util/netutils" @@ -37,6 +39,7 @@ import ( "yunion.io/x/onecloud/pkg/hostman/guestman/desc" "yunion.io/x/onecloud/pkg/hostman/hostinfo/hostconsts" "yunion.io/x/onecloud/pkg/hostman/options" + "yunion.io/x/onecloud/pkg/util/fileutils2" ) const ( @@ -386,11 +389,13 @@ func (s *SGuestMonitorCollector) reportIo(curInfo, prevInfo jsonutils.JSONObject if diffTime > 0 { for _, field := range fields { - cur, _ := curInfo.GetString(field) - prev, _ := prevInfo.GetString(field) - fcur, _ := strconv.ParseFloat(cur, 64) - fprev, _ := strconv.ParseFloat(prev, 64) - ioInfo.Set(s.GetIoFiledName(field), jsonutils.NewFloat64((fcur-fprev)/float64(diffTime))) + cur, _ := curInfo.Int(field) + prev, _ := prevInfo.Int(field) + diff := cur - prev + if diff < 0 { // if overflow int64 + diff = math.MaxInt64 - prev + cur + } + ioInfo.Set(s.GetIoFiledName(field), jsonutils.NewFloat64(float64(diff)/float64(diffTime))) } } return ioInfo @@ -461,6 +466,47 @@ func (m *SGuestMonitor) UpdateCpuCount(vcpuCount int) { m.CpuCnt = vcpuCount } +func (m *SGuestMonitor) GetSriovNicStats(pfName string, virtfn int) (*psnet.IOCountersStat, error) { + statsPath := fmt.Sprintf("/sys/class/net/%s/device/sriov/%d/stats", pfName, virtfn) + if !fileutils2.Exists(statsPath) { + return nil, nil + } + + stats, err := fileutils2.FileGetContents(statsPath) + if err != nil { + return nil, errors.Wrapf(err, "read file %s", statsPath) + } + res := new(psnet.IOCountersStat) + statsStr := string(stats) + for _, line := range strings.Split(statsStr, "\n") { + segs := strings.Split(line, ":") + if len(segs) != 2 { + continue + } + val, err := strconv.ParseUint(strings.TrimSpace(segs[1]), 10, 64) + if err != nil { + log.Errorf("failed parse %s", line) + continue + } + + switch strings.TrimSpace(segs[0]) { + case "tx_packets": + res.PacketsSent = val + case "tx_bytes": + res.BytesSent = val + case "tx_dropped": + res.Dropout = val + case "rx_packets": + res.PacketsRecv = val + case "rx_bytes": + res.BytesRecv = val + case "rx_dropped": + res.Dropin = val + } + } + return res, nil +} + func (m *SGuestMonitor) Netio() jsonutils.JSONObject { if len(m.Nics) == 0 { return nil @@ -472,19 +518,54 @@ func (m *SGuestMonitor) Netio() jsonutils.JSONObject { var res = jsonutils.NewArray() for i, nic := range m.Nics { - ifname := nic.Ifname + var ifname = nic.Ifname var nicStat *psnet.IOCountersStat - for j, netstat := range netstats { - if netstat.Name == ifname { - nicStat = &netstats[j] + if nic.Driver == "vfio-pci" { + if guest, ok := guestman.GetGuestManager().GetServer(m.Id); ok { + dev, err := guest.GetSriovDeviceByNetworkIndex(nic.Index) + if err != nil { + log.Errorf("failed get sriov deivce by network index %s", err) + continue + } + nicStat, err = m.GetSriovNicStats(dev.GetPfName(), dev.GetVirtfn()) + if err != nil { + log.Errorf("failed get sriov nic stats: %s", err) + continue + } + + } else { + continue + } + } else { + for j, netstat := range netstats { + if netstat.Name == ifname { + nicStat = &netstats[j] + } } } + if nicStat == nil { continue } data := jsonutils.NewDict() meta := jsonutils.NewDict() + // if overflow int64 + if nicStat.BytesSent > math.MaxInt64 { + nicStat.BytesSent -= math.MaxInt64 + } + if nicStat.BytesRecv > math.MaxInt64 { + nicStat.BytesRecv -= math.MaxInt64 + } + bitsRecv := nicStat.BytesRecv * 8 + if bitsRecv > math.MaxInt64 { + bitsRecv -= math.MaxInt64 + } + bitsSent := nicStat.BytesSent * 8 + if bitsSent > math.MaxInt64 { + bitsSent -= math.MaxInt64 + } + ip := nic.Ip ipv4, _ := netutils.NewIPV4Addr(ip) if netutils.IsExitAddress(ipv4) { @@ -492,7 +573,6 @@ func (m *SGuestMonitor) Netio() jsonutils.JSONObject { } else { meta.Set("ip_type", jsonutils.NewString("internal")) } - netId := nic.NetId meta.Set("ip", jsonutils.NewString(ip)) meta.Set("index", jsonutils.NewInt(int64(i))) @@ -501,8 +581,8 @@ func (m *SGuestMonitor) Netio() jsonutils.JSONObject { uptime, _ := host.Uptime() meta.Set("uptime", jsonutils.NewInt(int64(uptime))) data.Set("meta", meta) - data.Set("bits_recv", jsonutils.NewInt(int64(nicStat.BytesSent*8))) - data.Set("bits_sent", jsonutils.NewInt(int64(nicStat.BytesRecv*8))) + data.Set("bits_recv", jsonutils.NewInt(int64(bitsSent))) + data.Set("bits_sent", jsonutils.NewInt(int64(bitsRecv))) data.Set("packets_recv", jsonutils.NewInt(int64(nicStat.PacketsSent))) data.Set("packets_sent", jsonutils.NewInt(int64(nicStat.PacketsRecv))) data.Set("err_out", jsonutils.NewInt(int64(nicStat.Errin))) @@ -540,13 +620,35 @@ func (m *SGuestMonitor) Diskio() jsonutils.JSONObject { ret := jsonutils.NewDict() meta := jsonutils.NewDict() + // if overflow int64 + if io.ReadBytes > math.MaxInt64 { + io.ReadBytes -= math.MaxInt64 + } + if io.WriteBytes > math.MaxInt64 { + io.WriteBytes -= math.MaxInt64 + } + readBits := io.ReadBytes * 8 + if readBits > math.MaxInt64 { + readBits -= math.MaxInt64 + } + writeBits := io.WriteBytes * 8 + if writeBits > math.MaxInt64 { + writeBits -= math.MaxInt64 + } + if io.ReadCount > math.MaxInt64 { + io.ReadCount -= math.MaxInt64 + } + if io.WriteCount > math.MaxInt64 { + io.WriteCount -= math.MaxInt64 + } + uptime, _ := host.Uptime() meta.Set("uptime", jsonutils.NewInt(int64(uptime))) ret.Set("meta", meta) ret.Set("read_bytes", jsonutils.NewInt(int64(io.ReadBytes))) ret.Set("write_bytes", jsonutils.NewInt(int64(io.WriteBytes))) - ret.Set("read_bits", jsonutils.NewInt(int64(io.ReadBytes)*8)) - ret.Set("write_bits", jsonutils.NewInt(int64(io.WriteBytes)*8)) + ret.Set("read_bits", jsonutils.NewInt(int64(readBits))) + ret.Set("write_bits", jsonutils.NewInt(int64(writeBits))) ret.Set("read_count", jsonutils.NewInt(int64(io.ReadCount))) ret.Set("write_count", jsonutils.NewInt(int64(io.WriteCount))) return ret