feat(inputs.ethtool): Add support for link speed, duplex, autoneg and… (#12814)

This commit is contained in:
Simon Everts 2023-03-09 11:59:04 +01:00 committed by GitHub
parent 7981260f22
commit d063dc2e58
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 138 additions and 11 deletions

2
go.mod
View File

@ -147,7 +147,7 @@ require (
github.com/rabbitmq/amqp091-go v1.7.0 github.com/rabbitmq/amqp091-go v1.7.0
github.com/riemann/riemann-go-client v0.5.1-0.20211206220514-f58f10cdce16 github.com/riemann/riemann-go-client v0.5.1-0.20211206220514-f58f10cdce16
github.com/robbiet480/go.nut v0.0.0-20220219091450-bd8f121e1fa1 github.com/robbiet480/go.nut v0.0.0-20220219091450-bd8f121e1fa1
github.com/safchain/ethtool v0.0.0-20210803160452-9aa261dae9b1 github.com/safchain/ethtool v0.2.0
github.com/sensu/sensu-go/api/core/v2 v2.15.0 github.com/sensu/sensu-go/api/core/v2 v2.15.0
github.com/shirou/gopsutil/v3 v3.22.12 github.com/shirou/gopsutil/v3 v3.22.12
github.com/showwin/speedtest-go v1.4.2 github.com/showwin/speedtest-go v1.4.2

4
go.sum
View File

@ -2041,8 +2041,8 @@ github.com/ryanrolds/sqlclosecheck v0.3.0/go.mod h1:1gREqxyTGR3lVtpngyFo3hZAgk0K
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
github.com/safchain/ethtool v0.0.0-20210803160452-9aa261dae9b1 h1:ZFfeKAhIQiiOrQaI3/znw0gOmYpO28Tcu1YaqMa/jtQ= github.com/safchain/ethtool v0.2.0 h1:dILxMBqDnQfX192cCAPjZr9v2IgVXeElHPy435Z/IdE=
github.com/safchain/ethtool v0.0.0-20210803160452-9aa261dae9b1/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= github.com/safchain/ethtool v0.2.0/go.mod h1:WkKB1DnNtvsMlDmQ50sgwowDJV/hGbJSOvJoEXs1AJQ=
github.com/sagikazarmark/crypt v0.5.0/go.mod h1:l+nzl7KWh51rpzp2h7t4MZWyiEWdhNpOAnclKvg+mdA= github.com/sagikazarmark/crypt v0.5.0/go.mod h1:l+nzl7KWh51rpzp2h7t4MZWyiEWdhNpOAnclKvg+mdA=
github.com/sagikazarmark/crypt v0.6.0/go.mod h1:U8+INwJo3nBv1m6A/8OBXAq7Jnpspk5AxSgDyEQcea8= github.com/sagikazarmark/crypt v0.6.0/go.mod h1:U8+INwJo3nBv1m6A/8OBXAq7Jnpspk5AxSgDyEQcea8=
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=

View File

@ -101,6 +101,6 @@ Metrics are dependent on the network device and driver.
## Example Output ## Example Output
```shell ```shell
ethtool,driver=igb,host=test01,interface=mgmt0 tx_queue_1_packets=280782i,rx_queue_5_csum_err=0i,tx_queue_4_restart=0i,tx_multicast=7i,tx_queue_1_bytes=39674885i,rx_queue_2_alloc_failed=0i,tx_queue_5_packets=173970i,tx_single_coll_ok=0i,rx_queue_1_drops=0i,tx_queue_2_restart=0i,tx_aborted_errors=0i,rx_queue_6_csum_err=0i,tx_queue_5_restart=0i,tx_queue_4_bytes=64810835i,tx_abort_late_coll=0i,tx_queue_4_packets=109102i,os2bmc_tx_by_bmc=0i,tx_bytes=427527435i,tx_queue_7_packets=66665i,dropped_smbus=0i,rx_queue_0_csum_err=0i,tx_flow_control_xoff=0i,rx_packets=25926536i,rx_queue_7_csum_err=0i,rx_queue_3_bytes=84326060i,rx_multicast=83771i,rx_queue_4_alloc_failed=0i,rx_queue_3_drops=0i,rx_queue_3_csum_err=0i,rx_errors=0i,tx_errors=0i,tx_queue_6_packets=183236i,rx_broadcast=24378893i,rx_queue_7_packets=88680i,tx_dropped=0i,rx_frame_errors=0i,tx_queue_3_packets=161045i,tx_packets=1257017i,rx_queue_1_csum_err=0i,tx_window_errors=0i,tx_dma_out_of_sync=0i,rx_length_errors=0i,rx_queue_5_drops=0i,tx_timeout_count=0i,rx_queue_4_csum_err=0i,rx_flow_control_xon=0i,tx_heartbeat_errors=0i,tx_flow_control_xon=0i,collisions=0i,tx_queue_0_bytes=29465801i,rx_queue_6_drops=0i,rx_queue_0_alloc_failed=0i,tx_queue_1_restart=0i,rx_queue_0_drops=0i,tx_broadcast=9i,tx_carrier_errors=0i,tx_queue_7_bytes=13777515i,tx_queue_7_restart=0i,rx_queue_5_bytes=50732006i,rx_queue_7_bytes=35744457i,tx_deferred_ok=0i,tx_multi_coll_ok=0i,rx_crc_errors=0i,rx_fifo_errors=0i,rx_queue_6_alloc_failed=0i,tx_queue_2_packets=175206i,tx_queue_0_packets=107011i,rx_queue_4_bytes=201364548i,rx_queue_6_packets=372573i,os2bmc_rx_by_host=0i,multicast=83771i,rx_queue_4_drops=0i,rx_queue_5_packets=130535i,rx_queue_6_bytes=139488035i,tx_fifo_errors=0i,tx_queue_5_bytes=84899130i,rx_queue_0_packets=24529563i,rx_queue_3_alloc_failed=0i,rx_queue_7_drops=0i,tx_queue_6_bytes=96288614i,tx_queue_2_bytes=22132949i,tx_tcp_seg_failed=0i,rx_queue_1_bytes=246703840i,rx_queue_0_bytes=1506870738i,tx_queue_0_restart=0i,rx_queue_2_bytes=111344804i,tx_tcp_seg_good=0i,tx_queue_3_restart=0i,rx_no_buffer_count=0i,rx_smbus=0i,rx_queue_1_packets=273865i,rx_over_errors=0i,os2bmc_tx_by_host=0i,rx_queue_1_alloc_failed=0i,rx_queue_7_alloc_failed=0i,rx_short_length_errors=0i,tx_hwtstamp_timeouts=0i,tx_queue_6_restart=0i,rx_queue_2_packets=207136i,tx_queue_3_bytes=70391970i,rx_queue_3_packets=112007i,rx_queue_4_packets=212177i,tx_smbus=0i,rx_long_byte_count=2480280632i,rx_queue_2_csum_err=0i,rx_missed_errors=0i,rx_bytes=2480280632i,rx_queue_5_alloc_failed=0i,rx_queue_2_drops=0i,os2bmc_rx_by_bmc=0i,rx_align_errors=0i,rx_long_length_errors=0i,interface_up=1i,rx_hwtstamp_cleared=0i,rx_flow_control_xoff=0i 1564658080000000000 ethtool,driver=igb,host=test01,interface=mgmt0 tx_queue_1_packets=280782i,rx_queue_5_csum_err=0i,tx_queue_4_restart=0i,tx_multicast=7i,tx_queue_1_bytes=39674885i,rx_queue_2_alloc_failed=0i,tx_queue_5_packets=173970i,tx_single_coll_ok=0i,rx_queue_1_drops=0i,tx_queue_2_restart=0i,tx_aborted_errors=0i,rx_queue_6_csum_err=0i,tx_queue_5_restart=0i,tx_queue_4_bytes=64810835i,tx_abort_late_coll=0i,tx_queue_4_packets=109102i,os2bmc_tx_by_bmc=0i,tx_bytes=427527435i,tx_queue_7_packets=66665i,dropped_smbus=0i,rx_queue_0_csum_err=0i,tx_flow_control_xoff=0i,rx_packets=25926536i,rx_queue_7_csum_err=0i,rx_queue_3_bytes=84326060i,rx_multicast=83771i,rx_queue_4_alloc_failed=0i,rx_queue_3_drops=0i,rx_queue_3_csum_err=0i,rx_errors=0i,tx_errors=0i,tx_queue_6_packets=183236i,rx_broadcast=24378893i,rx_queue_7_packets=88680i,tx_dropped=0i,rx_frame_errors=0i,tx_queue_3_packets=161045i,tx_packets=1257017i,rx_queue_1_csum_err=0i,tx_window_errors=0i,tx_dma_out_of_sync=0i,rx_length_errors=0i,rx_queue_5_drops=0i,tx_timeout_count=0i,rx_queue_4_csum_err=0i,rx_flow_control_xon=0i,tx_heartbeat_errors=0i,tx_flow_control_xon=0i,collisions=0i,tx_queue_0_bytes=29465801i,rx_queue_6_drops=0i,rx_queue_0_alloc_failed=0i,tx_queue_1_restart=0i,rx_queue_0_drops=0i,tx_broadcast=9i,tx_carrier_errors=0i,tx_queue_7_bytes=13777515i,tx_queue_7_restart=0i,rx_queue_5_bytes=50732006i,rx_queue_7_bytes=35744457i,tx_deferred_ok=0i,tx_multi_coll_ok=0i,rx_crc_errors=0i,rx_fifo_errors=0i,rx_queue_6_alloc_failed=0i,tx_queue_2_packets=175206i,tx_queue_0_packets=107011i,rx_queue_4_bytes=201364548i,rx_queue_6_packets=372573i,os2bmc_rx_by_host=0i,multicast=83771i,rx_queue_4_drops=0i,rx_queue_5_packets=130535i,rx_queue_6_bytes=139488035i,tx_fifo_errors=0i,tx_queue_5_bytes=84899130i,rx_queue_0_packets=24529563i,rx_queue_3_alloc_failed=0i,rx_queue_7_drops=0i,tx_queue_6_bytes=96288614i,tx_queue_2_bytes=22132949i,tx_tcp_seg_failed=0i,rx_queue_1_bytes=246703840i,rx_queue_0_bytes=1506870738i,tx_queue_0_restart=0i,rx_queue_2_bytes=111344804i,tx_tcp_seg_good=0i,tx_queue_3_restart=0i,rx_no_buffer_count=0i,rx_smbus=0i,rx_queue_1_packets=273865i,rx_over_errors=0i,os2bmc_tx_by_host=0i,rx_queue_1_alloc_failed=0i,rx_queue_7_alloc_failed=0i,rx_short_length_errors=0i,tx_hwtstamp_timeouts=0i,tx_queue_6_restart=0i,rx_queue_2_packets=207136i,tx_queue_3_bytes=70391970i,rx_queue_3_packets=112007i,rx_queue_4_packets=212177i,tx_smbus=0i,rx_long_byte_count=2480280632i,rx_queue_2_csum_err=0i,rx_missed_errors=0i,rx_bytes=2480280632i,rx_queue_5_alloc_failed=0i,rx_queue_2_drops=0i,os2bmc_rx_by_bmc=0i,rx_align_errors=0i,rx_long_length_errors=0i,interface_up=1i,rx_hwtstamp_cleared=0i,rx_flow_control_xoff=0i,speed=1000i,link=1i,duplex=1i,autoneg=1i 1564658080000000000
ethtool,driver=igb,host=test02,interface=mgmt0 rx_queue_2_bytes=111344804i,tx_queue_3_bytes=70439858i,multicast=83771i,rx_broadcast=24378975i,tx_queue_0_packets=107011i,rx_queue_6_alloc_failed=0i,rx_queue_6_drops=0i,rx_hwtstamp_cleared=0i,tx_window_errors=0i,tx_tcp_seg_good=0i,rx_queue_1_drops=0i,tx_queue_1_restart=0i,rx_queue_7_csum_err=0i,rx_no_buffer_count=0i,tx_queue_1_bytes=39675245i,tx_queue_5_bytes=84899130i,tx_broadcast=9i,rx_queue_1_csum_err=0i,tx_flow_control_xoff=0i,rx_queue_6_csum_err=0i,tx_timeout_count=0i,os2bmc_tx_by_bmc=0i,rx_queue_6_packets=372577i,rx_queue_0_alloc_failed=0i,tx_flow_control_xon=0i,rx_queue_2_drops=0i,tx_queue_2_packets=175206i,rx_queue_3_csum_err=0i,tx_abort_late_coll=0i,tx_queue_5_restart=0i,tx_dropped=0i,rx_queue_2_alloc_failed=0i,tx_multi_coll_ok=0i,rx_queue_1_packets=273865i,rx_flow_control_xon=0i,tx_single_coll_ok=0i,rx_length_errors=0i,rx_queue_7_bytes=35744457i,rx_queue_4_alloc_failed=0i,rx_queue_6_bytes=139488395i,rx_queue_2_csum_err=0i,rx_long_byte_count=2480288216i,rx_queue_1_alloc_failed=0i,tx_queue_0_restart=0i,rx_queue_0_csum_err=0i,tx_queue_2_bytes=22132949i,rx_queue_5_drops=0i,tx_dma_out_of_sync=0i,rx_queue_3_drops=0i,rx_queue_4_packets=212177i,tx_queue_6_restart=0i,rx_packets=25926650i,rx_queue_7_packets=88680i,rx_frame_errors=0i,rx_queue_3_bytes=84326060i,rx_short_length_errors=0i,tx_queue_7_bytes=13777515i,rx_queue_3_alloc_failed=0i,tx_queue_6_packets=183236i,rx_queue_0_drops=0i,rx_multicast=83771i,rx_queue_2_packets=207136i,rx_queue_5_csum_err=0i,rx_queue_5_packets=130535i,rx_queue_7_alloc_failed=0i,tx_smbus=0i,tx_queue_3_packets=161081i,rx_queue_7_drops=0i,tx_queue_2_restart=0i,tx_multicast=7i,tx_fifo_errors=0i,tx_queue_3_restart=0i,rx_long_length_errors=0i,tx_queue_6_bytes=96288614i,tx_queue_1_packets=280786i,tx_tcp_seg_failed=0i,rx_align_errors=0i,tx_errors=0i,rx_crc_errors=0i,rx_queue_0_packets=24529673i,rx_flow_control_xoff=0i,tx_queue_0_bytes=29465801i,rx_over_errors=0i,rx_queue_4_drops=0i,os2bmc_rx_by_bmc=0i,rx_smbus=0i,dropped_smbus=0i,tx_hwtstamp_timeouts=0i,rx_errors=0i,tx_queue_4_packets=109102i,tx_carrier_errors=0i,tx_queue_4_bytes=64810835i,tx_queue_4_restart=0i,rx_queue_4_csum_err=0i,tx_queue_7_packets=66665i,tx_aborted_errors=0i,rx_missed_errors=0i,tx_bytes=427575843i,collisions=0i,rx_queue_1_bytes=246703840i,rx_queue_5_bytes=50732006i,rx_bytes=2480288216i,os2bmc_rx_by_host=0i,rx_queue_5_alloc_failed=0i,rx_queue_3_packets=112007i,tx_deferred_ok=0i,os2bmc_tx_by_host=0i,tx_heartbeat_errors=0i,rx_queue_0_bytes=1506877506i,tx_queue_7_restart=0i,tx_packets=1257057i,rx_queue_4_bytes=201364548i,interface_up=0i,rx_fifo_errors=0i,tx_queue_5_packets=173970i 1564658090000000000 ethtool,driver=igb,host=test02,interface=mgmt0 rx_queue_2_bytes=111344804i,tx_queue_3_bytes=70439858i,multicast=83771i,rx_broadcast=24378975i,tx_queue_0_packets=107011i,rx_queue_6_alloc_failed=0i,rx_queue_6_drops=0i,rx_hwtstamp_cleared=0i,tx_window_errors=0i,tx_tcp_seg_good=0i,rx_queue_1_drops=0i,tx_queue_1_restart=0i,rx_queue_7_csum_err=0i,rx_no_buffer_count=0i,tx_queue_1_bytes=39675245i,tx_queue_5_bytes=84899130i,tx_broadcast=9i,rx_queue_1_csum_err=0i,tx_flow_control_xoff=0i,rx_queue_6_csum_err=0i,tx_timeout_count=0i,os2bmc_tx_by_bmc=0i,rx_queue_6_packets=372577i,rx_queue_0_alloc_failed=0i,tx_flow_control_xon=0i,rx_queue_2_drops=0i,tx_queue_2_packets=175206i,rx_queue_3_csum_err=0i,tx_abort_late_coll=0i,tx_queue_5_restart=0i,tx_dropped=0i,rx_queue_2_alloc_failed=0i,tx_multi_coll_ok=0i,rx_queue_1_packets=273865i,rx_flow_control_xon=0i,tx_single_coll_ok=0i,rx_length_errors=0i,rx_queue_7_bytes=35744457i,rx_queue_4_alloc_failed=0i,rx_queue_6_bytes=139488395i,rx_queue_2_csum_err=0i,rx_long_byte_count=2480288216i,rx_queue_1_alloc_failed=0i,tx_queue_0_restart=0i,rx_queue_0_csum_err=0i,tx_queue_2_bytes=22132949i,rx_queue_5_drops=0i,tx_dma_out_of_sync=0i,rx_queue_3_drops=0i,rx_queue_4_packets=212177i,tx_queue_6_restart=0i,rx_packets=25926650i,rx_queue_7_packets=88680i,rx_frame_errors=0i,rx_queue_3_bytes=84326060i,rx_short_length_errors=0i,tx_queue_7_bytes=13777515i,rx_queue_3_alloc_failed=0i,tx_queue_6_packets=183236i,rx_queue_0_drops=0i,rx_multicast=83771i,rx_queue_2_packets=207136i,rx_queue_5_csum_err=0i,rx_queue_5_packets=130535i,rx_queue_7_alloc_failed=0i,tx_smbus=0i,tx_queue_3_packets=161081i,rx_queue_7_drops=0i,tx_queue_2_restart=0i,tx_multicast=7i,tx_fifo_errors=0i,tx_queue_3_restart=0i,rx_long_length_errors=0i,tx_queue_6_bytes=96288614i,tx_queue_1_packets=280786i,tx_tcp_seg_failed=0i,rx_align_errors=0i,tx_errors=0i,rx_crc_errors=0i,rx_queue_0_packets=24529673i,rx_flow_control_xoff=0i,tx_queue_0_bytes=29465801i,rx_over_errors=0i,rx_queue_4_drops=0i,os2bmc_rx_by_bmc=0i,rx_smbus=0i,dropped_smbus=0i,tx_hwtstamp_timeouts=0i,rx_errors=0i,tx_queue_4_packets=109102i,tx_carrier_errors=0i,tx_queue_4_bytes=64810835i,tx_queue_4_restart=0i,rx_queue_4_csum_err=0i,tx_queue_7_packets=66665i,tx_aborted_errors=0i,rx_missed_errors=0i,tx_bytes=427575843i,collisions=0i,rx_queue_1_bytes=246703840i,rx_queue_5_bytes=50732006i,rx_bytes=2480288216i,os2bmc_rx_by_host=0i,rx_queue_5_alloc_failed=0i,rx_queue_3_packets=112007i,tx_deferred_ok=0i,os2bmc_tx_by_host=0i,tx_heartbeat_errors=0i,rx_queue_0_bytes=1506877506i,tx_queue_7_restart=0i,tx_packets=1257057i,rx_queue_4_bytes=201364548i,interface_up=0i,rx_fifo_errors=0i,tx_queue_5_packets=173970i,speed=1000i,link=1i,duplex=1i,autoneg=1i 1564658090000000000
``` ```

View File

@ -18,6 +18,7 @@ type Command interface {
DriverName(intf NamespacedInterface) (string, error) DriverName(intf NamespacedInterface) (string, error)
Interfaces(includeNamespaces bool) ([]NamespacedInterface, error) Interfaces(includeNamespaces bool) ([]NamespacedInterface, error)
Stats(intf NamespacedInterface) (map[string]uint64, error) Stats(intf NamespacedInterface) (map[string]uint64, error)
Get(intf NamespacedInterface) (map[string]uint64, error)
} }
type Ethtool struct { type Ethtool struct {

View File

@ -132,6 +132,16 @@ func (e *Ethtool) gatherEthtoolStats(iface NamespacedInterface, acc telegraf.Acc
fields[e.normalizeKey(k)] = v fields[e.normalizeKey(k)] = v
} }
cmdget, err := e.command.Get(iface)
if err != nil {
acc.AddError(fmt.Errorf("%q get: %w", iface.Name, err))
return
}
for k, v := range cmdget {
fields[e.normalizeKey(k)] = v
}
acc.AddFields(pluginName, fields, tags) acc.AddFields(pluginName, fields, tags)
} }
@ -221,6 +231,10 @@ func (c *CommandEthtool) Stats(intf NamespacedInterface) (stats map[string]uint6
return intf.Namespace.Stats(intf) return intf.Namespace.Stats(intf)
} }
func (c *CommandEthtool) Get(intf NamespacedInterface) (stats map[string]uint64, err error) {
return intf.Namespace.Get(intf)
}
func (c *CommandEthtool) Interfaces(includeNamespaces bool) ([]NamespacedInterface, error) { func (c *CommandEthtool) Interfaces(includeNamespaces bool) ([]NamespacedInterface, error) {
const namespaceDirectory = "/var/run/netns" const namespaceDirectory = "/var/run/netns"

View File

@ -24,6 +24,7 @@ type InterfaceMock struct {
Stat map[string]uint64 Stat map[string]uint64
LoopBack bool LoopBack bool
InterfaceUp bool InterfaceUp bool
CmdGet map[string]uint64
} }
type NamespaceMock struct { type NamespaceMock struct {
@ -46,6 +47,10 @@ func (n *NamespaceMock) Stats(_ NamespacedInterface) (map[string]uint64, error)
return nil, errors.New("it is a test bug to invoke this function") return nil, errors.New("it is a test bug to invoke this function")
} }
func (n *NamespaceMock) Get(_ NamespacedInterface) (map[string]uint64, error) {
return nil, errors.New("it is a test bug to invoke this function")
}
type CommandEthtoolMock struct { type CommandEthtoolMock struct {
InterfaceMap map[string]*InterfaceMock InterfaceMap map[string]*InterfaceMock
} }
@ -117,6 +122,14 @@ func (c *CommandEthtoolMock) Stats(intf NamespacedInterface) (map[string]uint64,
return nil, errors.New("interface not found") return nil, errors.New("interface not found")
} }
func (c *CommandEthtoolMock) Get(intf NamespacedInterface) (map[string]uint64, error) {
i := c.InterfaceMap[intf.Name]
if i != nil {
return i.CmdGet, nil
}
return nil, errors.New("interface not found")
}
func setup() { func setup() {
interfaceMap = make(map[string]*InterfaceMock) interfaceMap = make(map[string]*InterfaceMock)
@ -219,7 +232,13 @@ func setup() {
"tx_tso_fallbacks": 0, "tx_tso_fallbacks": 0,
"tx_tso_long_headers": 0, "tx_tso_long_headers": 0,
} }
eth1 := &InterfaceMock{"eth1", "driver1", "", eth1Stat, false, true} eth1Get := map[string]uint64{
"autoneg": 1,
"duplex": 1,
"link": 1,
"speed": 1000,
}
eth1 := &InterfaceMock{"eth1", "driver1", "", eth1Stat, false, true, eth1Get}
interfaceMap[eth1.Name] = eth1 interfaceMap[eth1.Name] = eth1
eth2Stat := map[string]uint64{ eth2Stat := map[string]uint64{
@ -321,7 +340,13 @@ func setup() {
"tx_tso_fallbacks": 0, "tx_tso_fallbacks": 0,
"tx_tso_long_headers": 0, "tx_tso_long_headers": 0,
} }
eth2 := &InterfaceMock{"eth2", "driver1", "", eth2Stat, false, false} eth2Get := map[string]uint64{
"autoneg": 0,
"duplex": 255,
"link": 0,
"speed": 9223372036854775807,
}
eth2 := &InterfaceMock{"eth2", "driver1", "", eth2Stat, false, false, eth2Get}
interfaceMap[eth2.Name] = eth2 interfaceMap[eth2.Name] = eth2
eth3Stat := map[string]uint64{ eth3Stat := map[string]uint64{
@ -423,7 +448,13 @@ func setup() {
"tx_tso_fallbacks": 0, "tx_tso_fallbacks": 0,
"tx_tso_long_headers": 0, "tx_tso_long_headers": 0,
} }
eth3 := &InterfaceMock{"eth3", "driver1", "namespace1", eth3Stat, false, true} eth3Get := map[string]uint64{
"autoneg": 1,
"duplex": 1,
"link": 1,
"speed": 1000,
}
eth3 := &InterfaceMock{"eth3", "driver1", "namespace1", eth3Stat, false, true, eth3Get}
interfaceMap[eth3.Name] = eth3 interfaceMap[eth3.Name] = eth3
eth4Stat := map[string]uint64{ eth4Stat := map[string]uint64{
@ -525,14 +556,26 @@ func setup() {
"tx_tso_fallbacks": 0, "tx_tso_fallbacks": 0,
"tx_tso_long_headers": 0, "tx_tso_long_headers": 0,
} }
eth4 := &InterfaceMock{"eth4", "driver1", "namespace2", eth4Stat, false, true} eth4Get := map[string]uint64{
"autoneg": 1,
"duplex": 1,
"link": 1,
"speed": 100,
}
eth4 := &InterfaceMock{"eth4", "driver1", "namespace2", eth4Stat, false, true, eth4Get}
interfaceMap[eth4.Name] = eth4 interfaceMap[eth4.Name] = eth4
// dummy loopback including dummy stat to ensure that the ignore feature is working // dummy loopback including dummy stat to ensure that the ignore feature is working
lo0Stat := map[string]uint64{ lo0Stat := map[string]uint64{
"dummy": 0, "dummy": 0,
} }
lo0 := &InterfaceMock{"lo0", "", "", lo0Stat, true, true} lo0Get := map[string]uint64{
"autoneg": 1,
"duplex": 1,
"link": 1,
"speed": 1000,
}
lo0 := &InterfaceMock{"lo0", "", "", lo0Stat, true, true, lo0Get}
interfaceMap[lo0.Name] = lo0 interfaceMap[lo0.Name] = lo0
c := &CommandEthtoolMock{interfaceMap} c := &CommandEthtoolMock{interfaceMap}
@ -573,6 +616,9 @@ func TestGather(t *testing.T) {
require.Len(t, acc.Metrics, 2) require.Len(t, acc.Metrics, 2)
expectedFieldsEth1 := toStringMapInterface(interfaceMap["eth1"].Stat) expectedFieldsEth1 := toStringMapInterface(interfaceMap["eth1"].Stat)
for k, v := range interfaceMap["eth1"].CmdGet {
expectedFieldsEth1[k] = v
}
expectedFieldsEth1["interface_up_counter"] = expectedFieldsEth1["interface_up"] expectedFieldsEth1["interface_up_counter"] = expectedFieldsEth1["interface_up"]
expectedFieldsEth1["interface_up"] = true expectedFieldsEth1["interface_up"] = true
@ -582,7 +628,11 @@ func TestGather(t *testing.T) {
"namespace": "", "namespace": "",
} }
acc.AssertContainsTaggedFields(t, pluginName, expectedFieldsEth1, expectedTagsEth1) acc.AssertContainsTaggedFields(t, pluginName, expectedFieldsEth1, expectedTagsEth1)
expectedFieldsEth2 := toStringMapInterface(interfaceMap["eth2"].Stat) expectedFieldsEth2 := toStringMapInterface(interfaceMap["eth2"].Stat)
for k, v := range interfaceMap["eth2"].CmdGet {
expectedFieldsEth2[k] = v
}
expectedFieldsEth2["interface_up_counter"] = expectedFieldsEth2["interface_up"] expectedFieldsEth2["interface_up_counter"] = expectedFieldsEth2["interface_up"]
expectedFieldsEth2["interface_up"] = false expectedFieldsEth2["interface_up"] = false
expectedTagsEth2 := map[string]string{ expectedTagsEth2 := map[string]string{
@ -608,6 +658,9 @@ func TestGatherIncludeInterfaces(t *testing.T) {
// Should contain eth1 // Should contain eth1
expectedFieldsEth1 := toStringMapInterface(interfaceMap["eth1"].Stat) expectedFieldsEth1 := toStringMapInterface(interfaceMap["eth1"].Stat)
for k, v := range interfaceMap["eth1"].CmdGet {
expectedFieldsEth1[k] = v
}
expectedFieldsEth1["interface_up_counter"] = expectedFieldsEth1["interface_up"] expectedFieldsEth1["interface_up_counter"] = expectedFieldsEth1["interface_up"]
expectedFieldsEth1["interface_up"] = true expectedFieldsEth1["interface_up"] = true
expectedTagsEth1 := map[string]string{ expectedTagsEth1 := map[string]string{
@ -619,6 +672,9 @@ func TestGatherIncludeInterfaces(t *testing.T) {
// Should not contain eth2 // Should not contain eth2
expectedFieldsEth2 := toStringMapInterface(interfaceMap["eth2"].Stat) expectedFieldsEth2 := toStringMapInterface(interfaceMap["eth2"].Stat)
for k, v := range interfaceMap["eth2"].CmdGet {
expectedFieldsEth2[k] = v
}
expectedFieldsEth2["interface_up_counter"] = expectedFieldsEth2["interface_up"] expectedFieldsEth2["interface_up_counter"] = expectedFieldsEth2["interface_up"]
expectedFieldsEth2["interface_up"] = false expectedFieldsEth2["interface_up"] = false
expectedTagsEth2 := map[string]string{ expectedTagsEth2 := map[string]string{
@ -644,6 +700,9 @@ func TestGatherIgnoreInterfaces(t *testing.T) {
// Should not contain eth1 // Should not contain eth1
expectedFieldsEth1 := toStringMapInterface(interfaceMap["eth1"].Stat) expectedFieldsEth1 := toStringMapInterface(interfaceMap["eth1"].Stat)
for k, v := range interfaceMap["eth1"].CmdGet {
expectedFieldsEth1[k] = v
}
expectedFieldsEth1["interface_up_counter"] = expectedFieldsEth1["interface_up"] expectedFieldsEth1["interface_up_counter"] = expectedFieldsEth1["interface_up"]
expectedFieldsEth1["interface_up"] = true expectedFieldsEth1["interface_up"] = true
expectedTagsEth1 := map[string]string{ expectedTagsEth1 := map[string]string{
@ -655,6 +714,9 @@ func TestGatherIgnoreInterfaces(t *testing.T) {
// Should contain eth2 // Should contain eth2
expectedFieldsEth2 := toStringMapInterface(interfaceMap["eth2"].Stat) expectedFieldsEth2 := toStringMapInterface(interfaceMap["eth2"].Stat)
for k, v := range interfaceMap["eth2"].CmdGet {
expectedFieldsEth2[k] = v
}
expectedFieldsEth2["interface_up_counter"] = expectedFieldsEth2["interface_up"] expectedFieldsEth2["interface_up_counter"] = expectedFieldsEth2["interface_up"]
expectedFieldsEth2["interface_up"] = false expectedFieldsEth2["interface_up"] = false
expectedTagsEth2 := map[string]string{ expectedTagsEth2 := map[string]string{
@ -679,6 +741,9 @@ func TestSkipMetricsForInterfaceDown(t *testing.T) {
require.Len(t, acc.Metrics, 1) require.Len(t, acc.Metrics, 1)
expectedFieldsEth1 := toStringMapInterface(interfaceMap["eth1"].Stat) expectedFieldsEth1 := toStringMapInterface(interfaceMap["eth1"].Stat)
for k, v := range interfaceMap["eth1"].CmdGet {
expectedFieldsEth1[k] = v
}
expectedFieldsEth1["interface_up_counter"] = expectedFieldsEth1["interface_up"] expectedFieldsEth1["interface_up_counter"] = expectedFieldsEth1["interface_up"]
expectedFieldsEth1["interface_up"] = true expectedFieldsEth1["interface_up"] = true
@ -705,6 +770,9 @@ func TestGatherIncludeNamespaces(t *testing.T) {
// Should contain eth3 // Should contain eth3
expectedFieldsEth3 := toStringMapInterface(interfaceMap["eth3"].Stat) expectedFieldsEth3 := toStringMapInterface(interfaceMap["eth3"].Stat)
for k, v := range interfaceMap["eth3"].CmdGet {
expectedFieldsEth3[k] = v
}
expectedFieldsEth3["interface_up_counter"] = expectedFieldsEth3["interface_up"] expectedFieldsEth3["interface_up_counter"] = expectedFieldsEth3["interface_up"]
expectedFieldsEth3["interface_up"] = true expectedFieldsEth3["interface_up"] = true
expectedTagsEth3 := map[string]string{ expectedTagsEth3 := map[string]string{
@ -716,6 +784,9 @@ func TestGatherIncludeNamespaces(t *testing.T) {
// Should not contain eth2 // Should not contain eth2
expectedFieldsEth2 := toStringMapInterface(interfaceMap["eth2"].Stat) expectedFieldsEth2 := toStringMapInterface(interfaceMap["eth2"].Stat)
for k, v := range interfaceMap["eth2"].CmdGet {
expectedFieldsEth2[k] = v
}
expectedFieldsEth2["interface_up_counter"] = expectedFieldsEth2["interface_up"] expectedFieldsEth2["interface_up_counter"] = expectedFieldsEth2["interface_up"]
expectedFieldsEth2["interface_up"] = false expectedFieldsEth2["interface_up"] = false
expectedTagsEth2 := map[string]string{ expectedTagsEth2 := map[string]string{
@ -741,6 +812,9 @@ func TestGatherIgnoreNamespaces(t *testing.T) {
// Should not contain eth4 // Should not contain eth4
expectedFieldsEth4 := toStringMapInterface(interfaceMap["eth4"].Stat) expectedFieldsEth4 := toStringMapInterface(interfaceMap["eth4"].Stat)
for k, v := range interfaceMap["eth4"].CmdGet {
expectedFieldsEth4[k] = v
}
expectedFieldsEth4["interface_up_counter"] = expectedFieldsEth4["interface_up"] expectedFieldsEth4["interface_up_counter"] = expectedFieldsEth4["interface_up"]
expectedFieldsEth4["interface_up"] = true expectedFieldsEth4["interface_up"] = true
expectedTagsEth4 := map[string]string{ expectedTagsEth4 := map[string]string{
@ -752,6 +826,9 @@ func TestGatherIgnoreNamespaces(t *testing.T) {
// Should contain eth2 // Should contain eth2
expectedFieldsEth2 := toStringMapInterface(interfaceMap["eth2"].Stat) expectedFieldsEth2 := toStringMapInterface(interfaceMap["eth2"].Stat)
for k, v := range interfaceMap["eth2"].CmdGet {
expectedFieldsEth2[k] = v
}
expectedFieldsEth2["interface_up_counter"] = expectedFieldsEth2["interface_up"] expectedFieldsEth2["interface_up_counter"] = expectedFieldsEth2["interface_up"]
expectedFieldsEth2["interface_up"] = false expectedFieldsEth2["interface_up"] = false
expectedTagsEth2 := map[string]string{ expectedTagsEth2 := map[string]string{
@ -763,6 +840,9 @@ func TestGatherIgnoreNamespaces(t *testing.T) {
// Should contain eth3 // Should contain eth3
expectedFieldsEth3 := toStringMapInterface(interfaceMap["eth3"].Stat) expectedFieldsEth3 := toStringMapInterface(interfaceMap["eth3"].Stat)
for k, v := range interfaceMap["eth3"].CmdGet {
expectedFieldsEth3[k] = v
}
expectedFieldsEth3["interface_up_counter"] = expectedFieldsEth3["interface_up"] expectedFieldsEth3["interface_up_counter"] = expectedFieldsEth3["interface_up"]
expectedFieldsEth3["interface_up"] = true expectedFieldsEth3["interface_up"] = true
expectedTagsEth3 := map[string]string{ expectedTagsEth3 := map[string]string{
@ -880,7 +960,7 @@ func TestNormalizedKeys(t *testing.T) {
} }
for _, c := range cases { for _, c := range cases {
eth0 := &InterfaceMock{"eth0", "e1000e", "", toStringMapUint(c.stats), false, true} eth0 := &InterfaceMock{"eth0", "e1000e", "", toStringMapUint(c.stats), false, true, map[string]uint64{}}
expectedTags := map[string]string{ expectedTags := map[string]string{
"interface": eth0.Name, "interface": eth0.Name,
"driver": eth0.DriverName, "driver": eth0.DriverName,

View File

@ -7,6 +7,7 @@ type Namespace interface {
Interfaces() ([]NamespacedInterface, error) Interfaces() ([]NamespacedInterface, error)
DriverName(intf NamespacedInterface) (string, error) DriverName(intf NamespacedInterface) (string, error)
Stats(intf NamespacedInterface) (map[string]uint64, error) Stats(intf NamespacedInterface) (map[string]uint64, error)
Get(intf NamespacedInterface) (map[string]uint64, error)
} }
type NamespacedInterface struct { type NamespacedInterface struct {

View File

@ -1,6 +1,7 @@
package ethtool package ethtool
import ( import (
"math"
"net" "net"
"runtime" "runtime"
@ -68,6 +69,36 @@ func (n *NamespaceGoroutine) Stats(intf NamespacedInterface) (map[string]uint64,
return driver.(map[string]uint64), err return driver.(map[string]uint64), err
} }
func (n *NamespaceGoroutine) Get(intf NamespacedInterface) (map[string]uint64, error) {
result, err := n.Do(func(n *NamespaceGoroutine) (interface{}, error) {
ecmd := ethtoolLib.EthtoolCmd{}
speed32, err := n.ethtoolClient.CmdGet(&ecmd, intf.Name)
if err != nil {
return nil, err
}
var speed = uint64(speed32)
if speed == math.MaxUint32 {
speed = math.MaxUint64
}
var link32 uint32
link32, err = n.ethtoolClient.LinkState(intf.Name)
if err != nil {
return nil, err
}
return map[string]uint64{
"speed": speed,
"duplex": uint64(ecmd.Duplex),
"autoneg": uint64(ecmd.Autoneg),
"link": uint64(link32),
}, nil
})
return result.(map[string]uint64), err
}
// Start locks a goroutine to an OS thread and ties it to the namespace, then // Start locks a goroutine to an OS thread and ties it to the namespace, then
// loops for actions to run in the namespace. // loops for actions to run in the namespace.
func (n *NamespaceGoroutine) Start() error { func (n *NamespaceGoroutine) Start() error {