diff --git a/net/net.go b/net/net.go
index 0f3a62f39..36145c8bb 100644
--- a/net/net.go
+++ b/net/net.go
@@ -11,17 +11,19 @@ import (
var invoke common.Invoker = common.Invoke{}
type IOCountersStat struct {
- Name string `json:"name"` // interface name
- BytesSent uint64 `json:"bytesSent"` // number of bytes sent
- BytesRecv uint64 `json:"bytesRecv"` // number of bytes received
- PacketsSent uint64 `json:"packetsSent"` // number of packets sent
- PacketsRecv uint64 `json:"packetsRecv"` // number of packets received
- Errin uint64 `json:"errin"` // total number of errors while receiving
- Errout uint64 `json:"errout"` // total number of errors while sending
- Dropin uint64 `json:"dropin"` // total number of incoming packets which were dropped
- Dropout uint64 `json:"dropout"` // total number of outgoing packets which were dropped (always 0 on OSX and BSD)
- Fifoin uint64 `json:"fifoin"` // total number of FIFO buffers errors while receiving
- Fifoout uint64 `json:"fifoout"` // total number of FIFO buffers errors while sending
+ Name string `json:"name"` // interface name
+ BytesSent uint64 `json:"bytesSent"` // number of bytes sent
+ BytesRecv uint64 `json:"bytesRecv"` // number of bytes received
+ PacketsSent uint64 `json:"packetsSent"` // number of packets sent
+ PacketsRecv uint64 `json:"packetsRecv"` // number of packets received
+ Errin uint64 `json:"errin"` // total number of errors while receiving
+ Errout uint64 `json:"errout"` // total number of errors while sending
+ Dropin uint64 `json:"dropin"` // total number of incoming packets which were dropped
+ Dropout uint64 `json:"dropout"` // total number of outgoing packets which were dropped (always 0 on OSX and BSD)
+ Fifoin uint64 `json:"fifoin"` // total number of FIFO buffers errors while receiving
+ Fifoout uint64 `json:"fifoout"` // total number of FIFO buffers errors while sending
+ TransmitSpeed uint64 `json:"transmitSpeed"` // transmission speed of interface
+ ReceiveSpeed uint64 `json:"receiveSpeed"` // receiving speed of interface
}
// Addr is implemented compatibility to psutil
diff --git a/net/net_darwin.go b/net/net_darwin.go
index 4d2cfbcd8..fac6187a9 100644
--- a/net/net_darwin.go
+++ b/net/net_darwin.go
@@ -124,6 +124,44 @@ func parseNetstatOutput(output string) ([]netstatInterface, error) {
return interfaces, nil
}
+func parseIfconfigBlock(block string) uint64 {
+
+ re := regexp.MustCompile(`media:\s+.*\((\d+)baseT`)
+ match := re.FindStringSubmatch(block)
+
+ if len(match) >= 2 {
+ speed, err := strconv.ParseUint(match[1], 10, 64)
+ if err != nil {
+ speed = 0
+ }
+
+ return speed
+ }
+
+ return 0
+
+}
+
+func parseIfconfigOutput(output string, stats []IOCountersStat) error {
+
+ re := regexp.MustCompile(`(?m)^(\w+):.*(?:\n\t.+)*`)
+
+ matches := re.FindAllStringSubmatch(output, -1)
+ ifconfigBlock := map[string]string{}
+
+ for _, match := range matches {
+ ifconfigBlock[match[1]] = match[0]
+ }
+
+ for i, _ := range stats {
+ speed := parseIfconfigBlock(ifconfigBlock[stats[i].Name])
+ stats[i].TransmitSpeed = speed
+ stats[i].ReceiveSpeed = speed
+ }
+
+ return nil
+}
+
// map that hold the name of a network interface and the number of usage
type mapInterfaceNameUsage map[string]uint
@@ -247,6 +285,15 @@ func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat,
}
}
+ out, err = invoke.CommandWithContext(ctx, "ifconfig", "-a")
+ if err != nil {
+ return nil, err
+ }
+ err = parseIfconfigOutput(string(out), ret)
+ if err != nil {
+ return nil, err
+ }
+
if pernic == false {
return getIOCountersAll(ret)
}
diff --git a/net/net_darwin_test.go b/net/net_darwin_test.go
index 0680d08ad..f89952689 100644
--- a/net/net_darwin_test.go
+++ b/net/net_darwin_test.go
@@ -28,6 +28,27 @@ gif0* 1280 0 0 0 0
stf0* 1280 0 0 0 0 0 0 0 0
en0 1500 a8:66:7f:dd:ee:ff 5708989 0 7295722068 3494252 0 379533492 0 230
en0 1500 fe80::aa66: fe80:4::aa66:7fff 5708989 - 7295722068 3494252 - 379533492 - -`
+ ifconfigOutput = `lo0: flags=8049 mtu 16384
+ options=1203
+ inet 192.168.0.100 netmask 255.255.255.0
+ inet6 fe80::1234:5678:abcd:ef01%lo0 prefixlen 64 scopeid 0x1
+ inet6 fe80::5678:abcd:ef01:1234%lo0 prefixlen 64 scopeid 0x1
+ nd6 options=201
+gif0: flags=8010 mtu 1280
+stf0: flags=0<> mtu 1280
+en0: flags=8863 mtu 1500
+ ether 11:22:33:44:55:66
+ inet6 fe80::abcd:1234:5678:ef01%en0 prefixlen 64 secured scopeid 0x4
+ inet 192.168.1.100 netmask 255.255.255.0 broadcast 192.168.1.255
+ nd6 options=201
+ media: autoselect (1000baseT )
+ status: active
+utun0: flags=8051 mtu 1380
+ inet6 fe80::1234:5678:abcd:ef01%utun0 prefixlen 64 scopeid 0x5
+ nd6 options=201
+utun1: flags=8051 mtu 2000
+ inet6 fe80::abcd:5678:ef01:1234%utun1 prefixlen 64 scopeid 0x6
+ nd6 options=201`
)
func TestParseNetstatLineHeader(t *testing.T) {
@@ -138,3 +159,23 @@ func TestParseNetstatTruncated(t *testing.T) {
assert.True(t, mapUsage.isTruncated())
assert.Equal(t, 3, len(mapUsage.notTruncated()), "en0, gif0 and stf0")
}
+
+func TestParseIfconfigOutput(t *testing.T) {
+ testStats := []IOCountersStat{
+ {Name: "lo0"},
+ {Name: "en0"},
+ }
+ err := parseIfconfigOutput(ifconfigOutput, testStats)
+ assert.NoError(t, err)
+ assert.Len(t, testStats, 2)
+
+ assert.NotNil(t, testStats[0].TransmitSpeed)
+ assert.Equal(t, uint64(0), testStats[0].TransmitSpeed)
+ assert.NotNil(t, testStats[0].ReceiveSpeed)
+ assert.Equal(t, uint64(0), testStats[0].ReceiveSpeed)
+
+ assert.NotNil(t, testStats[1].TransmitSpeed)
+ assert.Equal(t, uint64(1000), testStats[1].TransmitSpeed)
+ assert.NotNil(t, testStats[1].ReceiveSpeed)
+ assert.Equal(t, uint64(1000), testStats[1].ReceiveSpeed)
+}
diff --git a/net/net_freebsd.go b/net/net_freebsd.go
index bf8baf094..93b5193f6 100644
--- a/net/net_freebsd.go
+++ b/net/net_freebsd.go
@@ -5,6 +5,8 @@ package net
import (
"context"
+ "os/exec"
+ "regexp"
"strconv"
"strings"
@@ -80,6 +82,10 @@ func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat,
BytesSent: parsed[6],
Dropout: parsed[7],
}
+ err := parseIfconfigOutput(&n)
+ if err != nil {
+ return nil, err
+ }
ret = append(ret, n)
}
@@ -90,6 +96,27 @@ func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat,
return ret, nil
}
+func parseIfconfigOutput(istat *IOCountersStat) error {
+ cmd := exec.Command("ifconfig", istat.Name)
+ out, err := cmd.Output()
+ if err != nil {
+ return err
+ }
+
+ re := regexp.MustCompile(`media:\s+.*\((\d+)baseT`)
+ match := re.FindStringSubmatch(string(out))
+ if len(match) >= 2 {
+ speed, err := strconv.ParseUint(match[1], 10, 64)
+ if err != nil {
+ speed = 0
+ }
+ istat.TransmitSpeed = speed
+ istat.ReceiveSpeed = speed
+ }
+
+ return nil
+}
+
// IOCountersByFile exists just for compatibility with Linux.
func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) {
return IOCountersByFileWithContext(context.Background(), pernic, filename)
diff --git a/net/net_linux.go b/net/net_linux.go
index dd62d4791..8228c4401 100644
--- a/net/net_linux.go
+++ b/net/net_linux.go
@@ -83,6 +83,18 @@ func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename stri
continue
}
+ speed, err := common.ReadLines(common.HostSys(fmt.Sprintf("class/net/%s/speed", interfaceName)))
+ if err != nil {
+ if strings.Contains(err.Error(), "no such file or directory") {
+ speed = []string{"0"}
+ } else {
+ return ret, err
+ }
+ }
+ if len(speed) == 0 || speed[0] == "-1" {
+ speed = []string{"0"}
+ }
+
fields := strings.Fields(strings.TrimSpace(parts[1]))
bytesRecv, err := strconv.ParseUint(fields[0], 10, 64)
if err != nil {
@@ -124,19 +136,29 @@ func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename stri
if err != nil {
return ret, err
}
+ transmitSpeed, err := strconv.ParseUint(speed[0], 10, 64)
+ if err != nil {
+ return ret, err
+ }
+ receiveSpeed, err := strconv.ParseUint(speed[0], 10, 64)
+ if err != nil {
+ return ret, err
+ }
nic := IOCountersStat{
- Name: interfaceName,
- BytesRecv: bytesRecv,
- PacketsRecv: packetsRecv,
- Errin: errIn,
- Dropin: dropIn,
- Fifoin: fifoIn,
- BytesSent: bytesSent,
- PacketsSent: packetsSent,
- Errout: errOut,
- Dropout: dropOut,
- Fifoout: fifoOut,
+ Name: interfaceName,
+ BytesRecv: bytesRecv,
+ PacketsRecv: packetsRecv,
+ Errin: errIn,
+ Dropin: dropIn,
+ Fifoin: fifoIn,
+ BytesSent: bytesSent,
+ PacketsSent: packetsSent,
+ Errout: errOut,
+ Dropout: dropOut,
+ Fifoout: fifoOut,
+ TransmitSpeed: transmitSpeed,
+ ReceiveSpeed: receiveSpeed,
}
ret = append(ret, nic)
}
diff --git a/net/net_test.go b/net/net_test.go
index 72f4db9c5..4951dbb83 100644
--- a/net/net_test.go
+++ b/net/net_test.go
@@ -30,7 +30,7 @@ func TestNetIOCountersStatString(t *testing.T) {
Name: "test",
BytesSent: 100,
}
- e := `{"name":"test","bytesSent":100,"bytesRecv":0,"packetsSent":0,"packetsRecv":0,"errin":0,"errout":0,"dropin":0,"dropout":0,"fifoin":0,"fifoout":0}`
+ e := `{"name":"test","bytesSent":100,"bytesRecv":0,"packetsSent":0,"packetsRecv":0,"errin":0,"errout":0,"dropin":0,"dropout":0,"fifoin":0,"fifoout":0,"transmitSpeed":0,"receiveSpeed":0}`
if e != fmt.Sprintf("%v", v) {
t.Errorf("NetIOCountersStat string is invalid: %v", v)
}
diff --git a/net/net_windows.go b/net/net_windows.go
index 5d384342f..3082d872c 100644
--- a/net/net_windows.go
+++ b/net/net_windows.go
@@ -167,6 +167,8 @@ func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat,
c.Errout = uint64(row.OutErrors)
c.Dropin = uint64(row.InDiscards)
c.Dropout = uint64(row.OutDiscards)
+ c.TransmitSpeed = uint64(row.TransmitLinkSpeed) / 1e6
+ c.ReceiveSpeed = uint64(row.ReceiveLinkSpeed) / 1e6
counters = append(counters, c)
}
@@ -189,6 +191,8 @@ func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat,
c.Errout = uint64(row.OutErrors)
c.Dropin = uint64(row.InDiscards)
c.Dropout = uint64(row.OutDiscards)
+ c.TransmitSpeed = uint64(row.Speed) / 1e6
+ c.ReceiveSpeed = uint64(row.Speed) / 1e6
counters = append(counters, c)
}