Commit 05fa791a authored by Sascha Steinbiss's avatar Sascha Steinbiss

New upstream version 0.0~git20170622.7ff1ba2

parents
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
language: go
This diff is collapsed.
# ethtool go package #
[![Build Status](https://travis-ci.org/safchain/ethtool.png?branch=master)](https://travis-ci.org/safchain/ethtool)
[![GoDoc](https://godoc.org/github.com/safchain/ethtool?status.svg)](https://godoc.org/github.com/safchain/ethtool)
The ethtool package aims to provide a library giving a simple access to the Linux SIOCETHTOOL ioctl operations. It can be used to retrieve informations from a network device like statistics, driver related informations or even the peer of a VETH interface.
## Build and Test ##
go get command:
go get github.com/safchain/ethtool
Testing
In order to run te
go test github.com/safchain/ethtool
## Examples ##
```go
package main
import (
"fmt"
"github.com/safchain/ethtool"
)
func main() {
ethHandle, err := ethtool.NewEthtool()
if err != nil {
panic(err.Error())
}
// Retrieve tx from eth0
stats, err := ethHandle.Stats("eth0")
if err != nil {
panic(err.Error())
}
fmt.Printf("TX: %d\n", stats["tx_bytes"])
// Retrieve peer index of a veth interface
stats, err = ethHandle.Stats("veth0")
if err != nil {
panic(err.Error())
}
fmt.Printf("Peer Index: %d\n", stats["peer_ifindex"])
}
```
## LICENSE ##
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
// Package ethtool aims to provide a library giving a simple access to the
// Linux SIOCETHTOOL ioctl operations. It can be used to retrieve informations
// from a network device like statistics, driver related informations or
// even the peer of a VETH interface.
package ethtool
import (
"bytes"
"fmt"
"syscall"
"unsafe"
)
// Maximum size of an interface name
const (
IFNAMSIZ = 16
)
// ioctl ethtool request
const (
SIOCETHTOOL = 0x8946
)
// ethtool stats related constants.
const (
ETH_GSTRING_LEN = 32
ETH_SS_STATS = 1
ETHTOOL_GDRVINFO = 0x00000003
ETHTOOL_GSTRINGS = 0x0000001b
ETHTOOL_GSTATS = 0x0000001d
// other CMDs from ethtool-copy.h of ethtool-3.5 package
ETHTOOL_GSET = 0x00000001 /* Get settings. */
ETHTOOL_SSET = 0x00000002 /* Set settings. */
ETHTOOL_GMSGLVL = 0x00000007 /* Get driver message level */
ETHTOOL_SMSGLVL = 0x00000008 /* Set driver msg level. */
)
// MAX_GSTRINGS maximum number of stats entries that ethtool can
// retrieve currently.
const (
MAX_GSTRINGS = 1000
)
type ifreq struct {
ifr_name [IFNAMSIZ]byte
ifr_data uintptr
}
type ethtoolDrvInfo struct {
cmd uint32
driver [32]byte
version [32]byte
fw_version [32]byte
bus_info [32]byte
erom_version [32]byte
reserved2 [12]byte
n_priv_flags uint32
n_stats uint32
testinfo_len uint32
eedump_len uint32
regdump_len uint32
}
type ethtoolGStrings struct {
cmd uint32
string_set uint32
len uint32
data [MAX_GSTRINGS * ETH_GSTRING_LEN]byte
}
type ethtoolStats struct {
cmd uint32
n_stats uint32
data [MAX_GSTRINGS]uint64
}
type Ethtool struct {
fd int
}
// DriverName returns the driver name of the given interface.
func (e *Ethtool) DriverName(intf string) (string, error) {
info, err := e.getDriverInfo(intf)
if err != nil {
return "", err
}
return string(bytes.Trim(info.driver[:], "\x00")), nil
}
// BusInfo returns the bus info of the given interface.
func (e *Ethtool) BusInfo(intf string) (string, error) {
info, err := e.getDriverInfo(intf)
if err != nil {
return "", err
}
return string(bytes.Trim(info.bus_info[:], "\x00")), nil
}
func (e *Ethtool) getDriverInfo(intf string) (ethtoolDrvInfo, error) {
drvinfo := ethtoolDrvInfo{
cmd: ETHTOOL_GDRVINFO,
}
var name [IFNAMSIZ]byte
copy(name[:], []byte(intf))
ifr := ifreq{
ifr_name: name,
ifr_data: uintptr(unsafe.Pointer(&drvinfo)),
}
_, _, ep := syscall.Syscall(syscall.SYS_IOCTL, uintptr(e.fd), SIOCETHTOOL, uintptr(unsafe.Pointer(&ifr)))
if ep != 0 {
return ethtoolDrvInfo{}, syscall.Errno(ep)
}
return drvinfo, nil
}
// Stats retrieves stats of the given interface name.
func (e *Ethtool) Stats(intf string) (map[string]uint64, error) {
drvinfo := ethtoolDrvInfo{
cmd: ETHTOOL_GDRVINFO,
}
var name [IFNAMSIZ]byte
copy(name[:], []byte(intf))
ifr := ifreq{
ifr_name: name,
ifr_data: uintptr(unsafe.Pointer(&drvinfo)),
}
_, _, ep := syscall.Syscall(syscall.SYS_IOCTL, uintptr(e.fd), SIOCETHTOOL, uintptr(unsafe.Pointer(&ifr)))
if ep != 0 {
return nil, syscall.Errno(ep)
}
if drvinfo.n_stats*ETH_GSTRING_LEN > MAX_GSTRINGS*ETH_GSTRING_LEN {
return nil, fmt.Errorf("ethtool currently doesn't support more than %d entries, received %d", MAX_GSTRINGS, drvinfo.n_stats)
}
gstrings := ethtoolGStrings{
cmd: ETHTOOL_GSTRINGS,
string_set: ETH_SS_STATS,
len: drvinfo.n_stats,
data: [MAX_GSTRINGS * ETH_GSTRING_LEN]byte{},
}
ifr.ifr_data = uintptr(unsafe.Pointer(&gstrings))
_, _, ep = syscall.Syscall(syscall.SYS_IOCTL, uintptr(e.fd), SIOCETHTOOL, uintptr(unsafe.Pointer(&ifr)))
if ep != 0 {
return nil, syscall.Errno(ep)
}
stats := ethtoolStats{
cmd: ETHTOOL_GSTATS,
n_stats: drvinfo.n_stats,
data: [MAX_GSTRINGS]uint64{},
}
ifr.ifr_data = uintptr(unsafe.Pointer(&stats))
_, _, ep = syscall.Syscall(syscall.SYS_IOCTL, uintptr(e.fd), SIOCETHTOOL, uintptr(unsafe.Pointer(&ifr)))
if ep != 0 {
return nil, syscall.Errno(ep)
}
var result = make(map[string]uint64)
for i := 0; i != int(drvinfo.n_stats); i++ {
b := gstrings.data[i*ETH_GSTRING_LEN : i*ETH_GSTRING_LEN+ETH_GSTRING_LEN]
key := string(bytes.Trim(b, "\x00"))
result[key] = stats.data[i]
}
return result, nil
}
func (e *Ethtool) Close() {
syscall.Close(e.fd)
}
func NewEthtool() (*Ethtool, error) {
fd, _, err := syscall.RawSyscall(syscall.SYS_SOCKET, syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_IP)
if err != 0 {
return nil, syscall.Errno(err)
}
return &Ethtool{
fd: int(fd),
}, nil
}
func BusInfo(intf string) (string, error) {
e, err := NewEthtool()
if err != nil {
return "", err
}
defer e.Close()
return e.BusInfo(intf)
}
func DriverName(intf string) (string, error) {
e, err := NewEthtool()
if err != nil {
return "", err
}
defer e.Close()
return e.DriverName(intf)
}
func Stats(intf string) (map[string]uint64, error) {
e, err := NewEthtool()
if err != nil {
return nil, err
}
defer e.Close()
return e.Stats(intf)
}
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
// Package ethtool aims to provide a library giving a simple access to the
// Linux SIOCETHTOOL ioctl operations. It can be used to retrieve informations
// from a network device like statistics, driver related informations or
// even the peer of a VETH interface.
package ethtool
import (
"reflect"
"syscall"
"unsafe"
)
type EthtoolCmd struct { /* ethtool.c: struct ethtool_cmd */
Cmd uint32
Supported uint32
Advertising uint32
Speed uint16
Duplex uint8
Port uint8
Phy_address uint8
Transceiver uint8
Autoneg uint8
Mdio_support uint8
Maxtxpkt uint32
Maxrxpkt uint32
Speed_hi uint16
Eth_tp_mdix uint8
Reserved2 uint8
Lp_advertising uint32
Reserved [2]uint32
}
// CmdGet returns the interface settings in the receiver struct
// and returns speed
func (ecmd *EthtoolCmd) CmdGet(intf string) (uint32, error) {
e, err := NewEthtool()
if err != nil {
return 0, err
}
defer e.Close()
return e.CmdGet(ecmd, intf)
}
// CmdSet sets and returns the settings in the receiver struct
// and returns speed
func (ecmd *EthtoolCmd) CmdSet(intf string) (uint32, error) {
e, err := NewEthtool()
if err != nil {
return 0, err
}
defer e.Close()
return e.CmdSet(ecmd, intf)
}
func (f *EthtoolCmd) reflect(retv *map[string]uint64) {
val := reflect.ValueOf(f).Elem()
for i := 0; i < val.NumField(); i++ {
valueField := val.Field(i)
typeField := val.Type().Field(i)
t := valueField.Interface()
//tt := reflect.TypeOf(t)
//fmt.Printf(" t %T %v tt %T %v\n", t, t, tt, tt)
switch t.(type) {
case uint32:
//fmt.Printf(" t is uint32\n")
(*retv)[typeField.Name] = uint64(t.(uint32))
case uint16:
(*retv)[typeField.Name] = uint64(t.(uint16))
case uint8:
(*retv)[typeField.Name] = uint64(t.(uint8))
case int32:
(*retv)[typeField.Name] = uint64(t.(int32))
case int16:
(*retv)[typeField.Name] = uint64(t.(int16))
case int8:
(*retv)[typeField.Name] = uint64(t.(int8))
default:
(*retv)[typeField.Name+"_unknown_type"] = 0
}
//tag := typeField.Tag
//fmt.Printf("Field Name: %s,\t Field Value: %v,\t Tag Value: %s\n",
// typeField.Name, valueField.Interface(), tag.Get("tag_name"))
}
}
// CmdGet returns the interface settings in the receiver struct
// and returns speed
func (e *Ethtool) CmdGet(ecmd *EthtoolCmd, intf string) (uint32, error) {
ecmd.Cmd = ETHTOOL_GSET
var name [IFNAMSIZ]byte
copy(name[:], []byte(intf))
ifr := ifreq{
ifr_name: name,
ifr_data: uintptr(unsafe.Pointer(ecmd)),
}
_, _, ep := syscall.Syscall(syscall.SYS_IOCTL, uintptr(e.fd),
SIOCETHTOOL, uintptr(unsafe.Pointer(&ifr)))
if ep != 0 {
return 0, syscall.Errno(ep)
}
var speedval uint32 = (uint32(ecmd.Speed_hi) << 16) |
(uint32(ecmd.Speed) & 0xffff)
return speedval, nil
}
// CmdSet sets and returns the settings in the receiver struct
// and returns speed
func (e *Ethtool) CmdSet(ecmd *EthtoolCmd, intf string) (uint32, error) {
ecmd.Cmd = ETHTOOL_SSET
var name [IFNAMSIZ]byte
copy(name[:], []byte(intf))
ifr := ifreq{
ifr_name: name,
ifr_data: uintptr(unsafe.Pointer(ecmd)),
}
_, _, ep := syscall.Syscall(syscall.SYS_IOCTL, uintptr(e.fd),
SIOCETHTOOL, uintptr(unsafe.Pointer(&ifr)))
if ep != 0 {
return 0, syscall.Errno(ep)
}
var speedval uint32 = (uint32(ecmd.Speed_hi) << 16) |
(uint32(ecmd.Speed) & 0xffff)
return speedval, nil
}
// CmdGetMapped returns the interface settings in a map
func (e *Ethtool) CmdGetMapped(intf string) (map[string]uint64, error) {
ecmd := EthtoolCmd{
Cmd: ETHTOOL_GSET,
}
var name [IFNAMSIZ]byte
copy(name[:], []byte(intf))
ifr := ifreq{
ifr_name: name,
ifr_data: uintptr(unsafe.Pointer(&ecmd)),
}
_, _, ep := syscall.Syscall(syscall.SYS_IOCTL, uintptr(e.fd),
SIOCETHTOOL, uintptr(unsafe.Pointer(&ifr)))
if ep != 0 {
return nil, syscall.Errno(ep)
}
var result = make(map[string]uint64)
// ref https://gist.github.com/drewolson/4771479
// Golang Reflection Example
ecmd.reflect(&result)
var speedval uint32 = (uint32(ecmd.Speed_hi) << 16) |
(uint32(ecmd.Speed) & 0xffff)
result["speed"] = uint64(speedval)
return result, nil
}
func CmdGetMapped(intf string) (map[string]uint64, error) {
e, err := NewEthtool()
if err != nil {
return nil, err
}
defer e.Close()
return e.CmdGetMapped(intf)
}
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package ethtool
import (
"net"
"testing"
)
func TestCmdGet(t *testing.T) {
intfs, err := net.Interfaces()
if err != nil {
t.Fatal(err)
}
// we expected to have at least one success
success := false
for _, intf := range intfs {
var ecmd EthtoolCmd
_, err := ecmd.CmdGet(intf.Name)
if err == nil {
success = true
}
}
if !success {
t.Fatal("Unable to get settings from any interface of this system.")
}
}
func TestCmdGetMapped(t *testing.T) {
intfs, err := net.Interfaces()
if err != nil {
t.Fatal(err)
}
// we expected to have at least one success
success := false
for _, intf := range intfs {
_, err := CmdGetMapped(intf.Name)
if err == nil {
success = true
}
}
if !success {
t.Fatal("Unable to get settings map from any interface of this system.")
}
}
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
// Package ethtool aims to provide a library giving a simple access to the
// Linux SIOCETHTOOL ioctl operations. It can be used to retrieve informations
// from a network device like statistics, driver related informations or
// even the peer of a VETH interface.
package ethtool
import (
"syscall"
"unsafe"
)
type ethtoolValue struct { /* ethtool.c: struct ethtool_value */
cmd uint32
data uint32
}
// MsglvlGet returns the msglvl of the given interface.
func (e *Ethtool) MsglvlGet(intf string) (uint32, error) {
edata := ethtoolValue{
cmd: ETHTOOL_GMSGLVL,
}
var name [IFNAMSIZ]byte
copy(name[:], []byte(intf))
ifr := ifreq{
ifr_name: name,
ifr_data: uintptr(unsafe.Pointer(&edata)),
}
_, _, ep := syscall.Syscall(syscall.SYS_IOCTL, uintptr(e.fd),
SIOCETHTOOL, uintptr(unsafe.Pointer(&ifr)))
if ep != 0 {
return 0, syscall.Errno(ep)
}
return edata.data, nil
}
// MsglvlSet returns the read-msglvl, post-set-msglvl of the given interface.
func (e *Ethtool) MsglvlSet(intf string, valset uint32) (uint32, uint32, error) {
edata := ethtoolValue{
cmd: ETHTOOL_GMSGLVL,
}
var name [IFNAMSIZ]byte
copy(name[:], []byte(intf))
ifr := ifreq{
ifr_name: name,
ifr_data: uintptr(unsafe.Pointer(&edata)),
}
_, _, ep := syscall.Syscall(syscall.SYS_IOCTL, uintptr(e.fd),
SIOCETHTOOL, uintptr(unsafe.Pointer(&ifr)))
if ep != 0 {
return 0, 0, syscall.Errno(ep)
}
readval := edata.data
edata.cmd = ETHTOOL_SMSGLVL
edata.data = valset
_, _, ep = syscall.Syscall(syscall.SYS_IOCTL, uintptr(e.fd),
SIOCETHTOOL, uintptr(unsafe.Pointer(&ifr)))
if ep != 0 {
return 0, 0, syscall.Errno(ep)
}
return readval, edata.data, nil
}
// MsglvlGet returns the msglvl of the given interface.
func MsglvlGet(intf string) (uint32, error) {
e, err := NewEthtool()
if err != nil {
return 0, err
}
defer e.Close()
return e.MsglvlGet(intf)
}
// MsglvlSet returns the read-msglvl, post-set-msglvl of the given interface.
func MsglvlSet(intf string, valset uint32) (uint32, uint32, error) {
e, err := NewEthtool()
if err != nil {
return 0, 0, err
}
defer e.Close()
return e.MsglvlSet(intf, valset)
}
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an