Skip to content

Commit

Permalink
Merge pull request #64 from Asphaltt/master
Browse files Browse the repository at this point in the history
Add support for ring/pause/priv-flags
  • Loading branch information
safchain committed Sep 16, 2023
2 parents 68eacaa + 1b6ddcf commit fe4a519
Show file tree
Hide file tree
Showing 2 changed files with 180 additions and 38 deletions.
192 changes: 167 additions & 25 deletions ethtool.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,33 +47,40 @@ const (

// ethtool stats related constants.
const (
ETH_GSTRING_LEN = 32
ETH_SS_STATS = 1
ETH_SS_FEATURES = 4
ETH_GSTRING_LEN = 32
ETH_SS_STATS = 1
ETH_SS_PRIV_FLAGS = 2
ETH_SS_FEATURES = 4

// CMD supported
ETHTOOL_GSET = 0x00000001 /* Get settings. */
ETHTOOL_SSET = 0x00000002 /* Set settings. */
ETHTOOL_GDRVINFO = 0x00000003 /* Get driver info. */
ETHTOOL_GSTRINGS = 0x0000001b /* get specified string set */
ETHTOOL_GSTATS = 0x0000001d /* get NIC-specific statistics */
// 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. */
ETHTOOL_GCHANNELS = 0x0000003c /* Get no of channels */
ETHTOOL_SCHANNELS = 0x0000003d /* Set no of channels */
ETHTOOL_GCOALESCE = 0x0000000e /* Get coalesce config */
ETHTOOL_GMSGLVL = 0x00000007 /* Get driver message level */
ETHTOOL_SMSGLVL = 0x00000008 /* Set driver msg level. */

/* Get link status for host, i.e. whether the interface *and* the
* physical port (if there is one) are up (ethtool_value). */
* physical port (if there is one) are up (ethtool_value). */
ETHTOOL_GLINK = 0x0000000a
ETHTOOL_GMODULEINFO = 0x00000042 /* Get plug-in module information */
ETHTOOL_GMODULEEEPROM = 0x00000043 /* Get plug-in module eeprom */
ETHTOOL_GCOALESCE = 0x0000000e /* Get coalesce config */
ETHTOOL_GRINGPARAM = 0x00000010 /* Get ring parameters */
ETHTOOL_SRINGPARAM = 0x00000011 /* Set ring parameters. */
ETHTOOL_GPAUSEPARAM = 0x00000012 /* Get pause parameters */
ETHTOOL_SPAUSEPARAM = 0x00000013 /* Set pause parameters. */
ETHTOOL_GSTRINGS = 0x0000001b /* Get specified string set */
ETHTOOL_GSTATS = 0x0000001d /* Get NIC-specific statistics */
ETHTOOL_GPERMADDR = 0x00000020 /* Get permanent hardware address */
ETHTOOL_GFEATURES = 0x0000003a /* Get device offload settings */
ETHTOOL_SFEATURES = 0x0000003b /* Change device offload settings */
ETHTOOL_GFLAGS = 0x00000025 /* Get flags bitmap(ethtool_value) */
ETHTOOL_GPFLAGS = 0x00000027 /* Get driver-private flags bitmap */
ETHTOOL_SPFLAGS = 0x00000028 /* Set driver-private flags bitmap */
ETHTOOL_GSSET_INFO = 0x00000037 /* Get string set info */
ETHTOOL_GFEATURES = 0x0000003a /* Get device offload settings */
ETHTOOL_SFEATURES = 0x0000003b /* Change device offload settings */
ETHTOOL_GCHANNELS = 0x0000003c /* Get no of channels */
ETHTOOL_SCHANNELS = 0x0000003d /* Set no of channels */
ETHTOOL_GET_TS_INFO = 0x00000041 /* Get time stamping and PHC info */
ETHTOOL_GMODULEINFO = 0x00000042 /* Get plug-in module information */
ETHTOOL_GMODULEEEPROM = 0x00000043 /* Get plug-in module eeprom */
)

// MAX_GSTRINGS maximum number of stats entries that ethtool can
Expand Down Expand Up @@ -345,6 +352,27 @@ type ethtoolPermAddr struct {
data [PERMADDR_LEN]byte
}

// Ring is a ring config for an interface
type Ring struct {
Cmd uint32
RxMaxPending uint32
RxMiniMaxPending uint32
RxJumboMaxPending uint32
TxMaxPending uint32
RxPending uint32
RxMiniPending uint32
RxJumboPending uint32
TxPending uint32
}

// Pause is a pause config for an interface
type Pause struct {
Cmd uint32
Autoneg uint32
RxPause uint32
TxPause uint32
}

type Ethtool struct {
fd int
}
Expand Down Expand Up @@ -597,6 +625,54 @@ func (e *Ethtool) getModuleEeprom(intf string) (ethtoolEeprom, ethtoolModInfo, e
return eeprom, modInfo, nil
}

// GetRing retrieves ring parameters of the given interface name.
func (e *Ethtool) GetRing(intf string) (Ring, error) {
ring := Ring{
Cmd: ETHTOOL_GRINGPARAM,
}

if err := e.ioctl(intf, uintptr(unsafe.Pointer(&ring))); err != nil {
return Ring{}, err
}

return ring, nil
}

// SetRing sets ring parameters of the given interface name.
func (e *Ethtool) SetRing(intf string, ring Ring) (Ring, error) {
ring.Cmd = ETHTOOL_SRINGPARAM

if err := e.ioctl(intf, uintptr(unsafe.Pointer(&ring))); err != nil {
return Ring{}, err
}

return ring, nil
}

// GetPause retrieves pause parameters of the given interface name.
func (e *Ethtool) GetPause(intf string) (Pause, error) {
pause := Pause{
Cmd: ETHTOOL_GPAUSEPARAM,
}

if err := e.ioctl(intf, uintptr(unsafe.Pointer(&pause))); err != nil {
return Pause{}, err
}

return pause, nil
}

// SetPause sets pause parameters of the given interface name.
func (e *Ethtool) SetPause(intf string, pause Pause) (Pause, error) {
pause.Cmd = ETHTOOL_SPAUSEPARAM

if err := e.ioctl(intf, uintptr(unsafe.Pointer(&pause))); err != nil {
return Pause{}, err
}

return pause, nil
}

func isFeatureBitSet(blocks [MAX_FEATURE_BLOCKS]ethtoolGetFeaturesBlock, index uint) bool {
return (blocks)[index/32].active&(1<<(index%32)) != 0
}
Expand All @@ -613,11 +689,10 @@ func setFeatureBit(blocks *[MAX_FEATURE_BLOCKS]ethtoolSetFeaturesBlock, index ui
}
}

// FeatureNames shows supported features by their name.
func (e *Ethtool) FeatureNames(intf string) (map[string]uint, error) {
func (e *Ethtool) getNames(intf string, mask int) (map[string]uint, error) {
ssetInfo := ethtoolSsetInfo{
cmd: ETHTOOL_GSSET_INFO,
sset_mask: 1 << ETH_SS_FEATURES,
sset_mask: 1 << mask,
}

if err := e.ioctl(intf, uintptr(unsafe.Pointer(&ssetInfo))); err != nil {
Expand All @@ -633,7 +708,7 @@ func (e *Ethtool) FeatureNames(intf string) (map[string]uint, error) {

gstrings := ethtoolGStrings{
cmd: ETHTOOL_GSTRINGS,
string_set: ETH_SS_FEATURES,
string_set: uint32(mask),
len: length,
data: [MAX_GSTRINGS * ETH_GSTRING_LEN]byte{},
}
Expand All @@ -642,7 +717,7 @@ func (e *Ethtool) FeatureNames(intf string) (map[string]uint, error) {
return nil, err
}

var result = make(map[string]uint)
result := make(map[string]uint)
for i := 0; i != int(length); i++ {
b := gstrings.data[i*ETH_GSTRING_LEN : i*ETH_GSTRING_LEN+ETH_GSTRING_LEN]
key := goString(b)
Expand All @@ -654,6 +729,11 @@ func (e *Ethtool) FeatureNames(intf string) (map[string]uint, error) {
return result, nil
}

// FeatureNames shows supported features by their name.
func (e *Ethtool) FeatureNames(intf string) (map[string]uint, error) {
return e.getNames(intf, ETH_SS_FEATURES)
}

// Features retrieves features of the given interface name.
func (e *Ethtool) Features(intf string) (map[string]bool, error) {
names, err := e.FeatureNames(intf)
Expand All @@ -675,7 +755,7 @@ func (e *Ethtool) Features(intf string) (map[string]bool, error) {
return nil, err
}

var result = make(map[string]bool, length)
result := make(map[string]bool, length)
for key, index := range names {
result[key] = isFeatureBitSet(features.blocks, index)
}
Expand Down Expand Up @@ -708,6 +788,68 @@ func (e *Ethtool) Change(intf string, config map[string]bool) error {
return e.ioctl(intf, uintptr(unsafe.Pointer(&features)))
}

// PrivFlagsNames shows supported private flags by their name.
func (e *Ethtool) PrivFlagsNames(intf string) (map[string]uint, error) {
return e.getNames(intf, ETH_SS_PRIV_FLAGS)
}

// PrivFlags retrieves private flags of the given interface name.
func (e *Ethtool) PrivFlags(intf string) (map[string]bool, error) {
names, err := e.PrivFlagsNames(intf)
if err != nil {
return nil, err
}

length := uint32(len(names))
if length == 0 {
return map[string]bool{}, nil
}

var val ethtoolLink
val.cmd = ETHTOOL_GPFLAGS
if err := e.ioctl(intf, uintptr(unsafe.Pointer(&val))); err != nil {
return nil, err
}

result := make(map[string]bool, length)
for name, mask := range names {
result[name] = val.data&(1<<mask) != 0
}

return result, nil
}

// UpdatePrivFlags requests a change in the given device's private flags.
func (e *Ethtool) UpdatePrivFlags(intf string, config map[string]bool) error {
names, err := e.PrivFlagsNames(intf)
if err != nil {
return err
}

var curr ethtoolLink
curr.cmd = ETHTOOL_GPFLAGS
if err := e.ioctl(intf, uintptr(unsafe.Pointer(&curr))); err != nil {
return err
}

var update ethtoolLink
update.cmd = ETHTOOL_SPFLAGS
update.data = curr.data
for name, value := range config {
if index, ok := names[name]; ok {
if value {
update.data |= 1 << index
} else {
update.data &= ^(1 << index)
}
} else {
return fmt.Errorf("unsupported priv flag %q", name)
}
}

return e.ioctl(intf, uintptr(unsafe.Pointer(&update)))
}

// Get state of a link.
func (e *Ethtool) LinkState(intf string) (uint32, error) {
x := ethtoolLink{
Expand Down Expand Up @@ -756,7 +898,7 @@ func (e *Ethtool) Stats(intf string) (map[string]uint64, error) {
return nil, err
}

var result = make(map[string]uint64)
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]
strEnd := strings.Index(string(b), "\x00")
Expand Down
26 changes: 13 additions & 13 deletions ethtool_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,28 +83,28 @@ func (f *EthtoolCmd) reflect(retv *map[string]uint64) {
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) {
// tt := reflect.TypeOf(t)
// fmt.Printf(" t %T %v tt %T %v\n", t, t, tt, tt)
switch tt := t.(type) {
case uint32:
//fmt.Printf(" t is uint32\n")
(*retv)[typeField.Name] = uint64(t.(uint32))
// fmt.Printf(" t is uint32\n")
(*retv)[typeField.Name] = uint64(tt)
case uint16:
(*retv)[typeField.Name] = uint64(t.(uint16))
(*retv)[typeField.Name] = uint64(tt)
case uint8:
(*retv)[typeField.Name] = uint64(t.(uint8))
(*retv)[typeField.Name] = uint64(tt)
case int32:
(*retv)[typeField.Name] = uint64(t.(int32))
(*retv)[typeField.Name] = uint64(tt)
case int16:
(*retv)[typeField.Name] = uint64(t.(int16))
(*retv)[typeField.Name] = uint64(tt)
case int8:
(*retv)[typeField.Name] = uint64(t.(int8))
(*retv)[typeField.Name] = uint64(tt)
default:
(*retv)[typeField.Name+"_unknown_type"] = 0
}

//tag := typeField.Tag
//fmt.Printf("Field Name: %s,\t Field Value: %v,\t Tag Value: %s\n",
// 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"))
}
}
Expand Down Expand Up @@ -185,7 +185,7 @@ func (e *Ethtool) CmdGetMapped(intf string) (map[string]uint64, error) {
return nil, ep
}

var result = make(map[string]uint64)
result := make(map[string]uint64)

// ref https://gist.github.com/drewolson/4771479
// Golang Reflection Example
Expand Down

0 comments on commit fe4a519

Please sign in to comment.